스프링 부트 백엔드 개발 강좌, 스프링 시큐리티로 로그인 로그아웃, 회원 가입 구현, 로그인, 회원 가입 실행 테스트하기

스프링 시큐리티로 로그인/로그아웃, 회원 가입 구현

안녕하세요, 오늘은 스프링 부트를 이용한 백엔드 개발 강좌를 진행하겠습니다. 본 강좌에서는 스프링 시큐리티를 활용하여 로그인과 로그아웃 기능, 그리고 회원 가입 기능을 구현하는 방법에 대해 자세히 알아보겠습니다. 스프링 부트는 자바 기반의 웹 애플리케이션을 신속하고 쉽게 개발할 수 있는 프레임워크이며, 이 것을 통해 강력하고 안전한 웹 애플리케이션을 만드는 과정에 대해 다룰 것입니다.

1. 개발 환경 설정

강좌에 앞서, 먼저 개발 환경을 설정해야 합니다. 다음은 필요한 도구와 설정 방법입니다.

  • Java Development Kit (JDK) 11 이상
  • Spring Boot 2.5.x 이상
  • IntelliJ IDEA 또는 Eclipse와 같은 IDE
  • Gradle 또는 Maven (빌드 도구)
  • H2 데이터베이스 (임베디드 데이터베이스)

2. 스프링 부트 프로젝트 생성

스프링 부트 프로젝트를 생성하기 위해 Spring Initializr를 사용합니다. 다음 단계를 따라 프로젝트를 만들어 주세요.

  1. 웹 브라우저에서 Spring Initializr에 접속합니다.
  2. 프로젝트 메타데이터를 입력합니다.
    • Project: Maven Project 또는 Gradle Project
    • Language: Java
    • Spring Boot: 2.x.x로 설정
    • Group: com.example
    • Artifact: demo
    • Name: demo
    • Description: Spring Boot demo project
    • Package name: com.example.demo
    • Packaging: Jar
    • Java: 11
  3. Dependencies에서 다음을 선택합니다.
    • Spring Web
    • Spring Security
    • Spring Data JPA
    • H2 Database
  4. Generate 버튼을 클릭하여 프로젝트 ZIP 파일을 다운로드합니다.

3. 프로젝트 구조

프로젝트를 열면 기본적인 패키지 구조가 생성되어 있습니다. 주요 디렉터리와 파일의 역할을 설명하겠습니다.

  • src/main/java/com/example/demo: 자바 소스 파일이 위치하는 디렉토리입니다.
  • src/main/resources/application.properties: 애플리케이션 설정 파일입니다.
  • src/test/java/com/example/demo: 테스트 파일이 위치하는 디렉토리입니다.

4. 스프링 시큐리티 설정

스프링 시큐리티를 설정하여 로그인과 로그아웃 기능을 구현하겠습니다.

4.1 Dependency 추가

pom.xml 또는 build.gradle 파일에 필요한 의존성을 추가합니다. 만약 Maven을 사용한다면 아래의 의존성을 추가해주세요.

        
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
        
    

4.2 SecurityConfig 클래스 생성

스프링 시큐리티의 설정을 정의하기 위해 SecurityConfig 클래스를 생성합니다.

        
            package com.example.demo.config;

            import org.springframework.context.annotation.Bean;
            import org.springframework.context.annotation.Configuration;
            import org.springframework.security.config.annotation.web.builders.HttpSecurity;
            import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
            import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

            @Configuration
            @EnableWebSecurity
            public class SecurityConfig extends WebSecurityConfigurerAdapter {
                
                @Override
                protected void configure(HttpSecurity http) throws Exception {
                    http
                        .authorizeRequests()
                        .antMatchers("/register", "/h2-console/**").permitAll()
                        .anyRequest().authenticated()
                        .and()
                        .formLogin()
                        .loginPage("/login")
                        .permitAll()
                        .and()
                        .logout()
                        .permitAll();
                }

                @Bean
                public void init() {
                    // H2 Console 사용을 위한 설정
                    java.sql.Connection conn = DriverManager.getConnection("jdbc:h2:mem:testdb", "sa", "");
                    conn.createStatement().execute("SET MODE MySQL");
                }
            }
        
    

5. 회원 가입 기능 구현

이제 기본적인 회원 가입 기능을 구현해 보겠습니다.

5.1 User 엔티티 생성

회원 정보를 저장할 User 엔티티 클래스를 생성합니다.

        
            package com.example.demo.model;

            import javax.persistence.Entity;
            import javax.persistence.GeneratedValue;
            import javax.persistence.GenerationType;
            import javax.persistence.Id;

            @Entity
            public class User {
                @Id
                @GeneratedValue(strategy = GenerationType.IDENTITY)
                private Long id;

                private String username;
                private String password;

                // getters and setters
            }
        
    

5.2 UserRepository 인터페이스 생성

회원 정보를 관리할 UserRepository를 생성합니다.

        
            package com.example.demo.repository;

            import com.example.demo.model.User;
            import org.springframework.data.jpa.repository.JpaRepository;

            public interface UserRepository extends JpaRepository {
                User findByUsername(String username);
            }
        
    

5.3 UserService 클래스 생성

회원 가입 로직을 처리할 UserService 클래스를 생성합니다.

        
            package com.example.demo.service;

            import com.example.demo.model.User;
            import com.example.demo.repository.UserRepository;
            import org.springframework.beans.factory.annotation.Autowired;
            import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
            import org.springframework.stereotype.Service;

            @Service
            public class UserService {
                @Autowired
                private UserRepository userRepository;

                @Autowired
                private BCryptPasswordEncoder passwordEncoder;

                public void register(User user) {
                    user.setPassword(passwordEncoder.encode(user.getPassword()));
                    userRepository.save(user);
                }

                public User findByUsername(String username) {
                    return userRepository.findByUsername(username);
                }
            }
        
    

5.4 RegistrationController 클래스 생성

회원 가입 페이지와 로직을 처리할 RegistrationController 클래스를 생성합니다.

        
            package com.example.demo.controller;

            import com.example.demo.model.User;
            import com.example.demo.service.UserService;
            import org.springframework.beans.factory.annotation.Autowired;
            import org.springframework.stereotype.Controller;
            import org.springframework.ui.Model;
            import org.springframework.web.bind.annotation.GetMapping;
            import org.springframework.web.bind.annotation.PostMapping;
            import org.springframework.web.bind.annotation.ModelAttribute;

            @Controller
            public class RegistrationController {

                @Autowired
                private UserService userService;

                @GetMapping("/register")
                public String showRegistrationForm(Model model) {
                    model.addAttribute("user", new User());
                    return "register";
                }

                @PostMapping("/register")
                public String registerUser(@ModelAttribute User user) {
                    userService.register(user);
                    return "redirect:/login";
                }
            }
        
    

5.5 HTML 뷰 템플릿 생성

회원 가입 HTML 뷰를 생성합니다. templates/register.html 파일을 다음과 같이 작성합니다.

        
            <!DOCTYPE html>
            <html xmlns:th="http://www.thymeleaf.org">
            <head>
                <title>회원 가입</title>
            </head>
            <body>
                <h1>회원 가입</h1>
                <form action="#" th:action="@{/register}" th:object="${user}" method="post">
                    <div>
                        <label for="username">사용자 이름:</label>
                        <input type="text" th:field="*{username}" required/>
                    </div>
                    <div>
                        <label for="password">비밀번호:</label>
                        <input type="password" th:field="*{password}" required/>
                    </div>
                    <div>
                        <button type="submit">가입하기</button>
                    </div>
                </form>
            </body>
            </html>
        
    

6. 로그인 기능 구현

이제 로그인 기능을 구현하겠습니다. 스프링 시큐리티에서는 사용자 인증을 처리해 주므로, 우리는 사용자 정보와 관련된 부분만 구현하면 됩니다.

6.1 SecurityConfig 변경

SecurityConfig에서 사용자 인증 정보를 설정합니다.

        
            import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;

            @Override
            protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                auth.userDetailsService(userDetailsService())
                    .passwordEncoder(passwordEncoder());
            }
        
    

6.2 UserDetailsService 구현

사용자의 인증 정보를 처리할 UserDetailsService를 생성합니다.

        
            package com.example.demo.service;

            import org.springframework.security.core.userdetails.UserDetails;
            import org.springframework.security.core.userdetails.UserDetailsService;
            import org.springframework.security.core.userdetails.UsernameNotFoundException;
            import org.springframework.stereotype.Service;

            @Service
            public class CustomUserDetailsService implements UserDetailsService {
                
                @Autowired
                private UserService userService;

                @Override
                public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                    User user = userService.findByUsername(username);
                    if (user == null) {
                        throw new UsernameNotFoundException("사용자를 찾을 수 없습니다: " + username);
                    }
                    return org.springframework.security.core.userdetails.User.withUsername(user.getUsername())
                            .password(user.getPassword())
                            .roles("USER")
                            .build();
                }
            }
        
    

7. 로그인 및 로그아웃 페이지

로그인 페이지와 로그아웃 확인 페이지를 구현합니다.

7.1 login.html 템플릿 생성

        
            <!DOCTYPE html>
            <html xmlns:th="http://www.thymeleaf.org">
            <head>
                <title>로그인</title>
            </head>
            <body>
                <h1>로그인</h1>
                <form action="#" th:action="@{/login}" method="post">
                    <div>
                        <label for="username">사용자 이름:</label>
                        <input type="text" name="username" required/>
                    </div>
                    <div>
                        <label for="password">비밀번호:</label>
                        <input type="password" name="password" required/>
                    </div>
                    <div>
                        <button type="submit">로그인</button>
                    </div>
                </form>
            </body>
            </html>
        
    

7.2 logout.html 템플릿 생성

        
            <!DOCTYPE html>
            <html xmlns:th="http://www.thymeleaf.org">
            <head>
                <title>로그아웃</title>
            </head>
            <body>
                <h1>로그아웃 되었습니다.</h1>
                <a href="/login">로그인 페이지로 이동</a>
            </body>
            </html>
        
    

8. 실행 및 테스트

이제 모든 설정과 구현을 마쳤으니, 애플리케이션을 실행하고 테스트해 보겠습니다.

8.1 애플리케이션 실행

애플리케이션을 실행합니다. IDE에서 Run 또는 Terminal을 통해 다음 명령어를 실행합니다.

        
            ./mvnw spring-boot:run
        
    

브라우저에서 http://localhost:8080/register를 입력하여 회원 가입 페이지로 이동합니다.

8.2 회원 가입 테스트

사용자 이름과 비밀번호를 입력하여 회원 가입을 테스트합니다. 가입 후, http://localhost:8080/login으로 이동하여 로그인 테스트를 진행합니다.

8.3 로그인 및 로그아웃 테스트

정상적으로 로그인한 후 로그아웃 버튼을 클릭하여 로그아웃이 잘 되는지 확인합니다.

9. 마무리

이번 강좌에서는 스프링 부트를 사용하여 스프링 시큐리티로 로그인, 로그아웃, 회원 가입 기능을 구현하는 방법을 배웠습니다. 이러한 기본 기능을 통해 여러분은 나만의 웹 애플리케이션을 안전하게 운영할 수 있는 기반을 마련했습니다. 스프링 부트를 활용한 다양한 기능들과 연동하여 더욱 발전된 웹 애플리케이션을 만들어 보세요!