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

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

안녕하세요! 이번 강좌에서는 스프링 부트스프링 시큐리티를 활용하여 기본적인 로그인/로그아웃 기능과 회원 가입 시스템을 구현해 보겠습니다. 이 강좌는 Java와 웹 개발에 대한 기본 지식이 있는 분들을 대상으로 하며, 실용적인 예제를 통해 배우실 수 있습니다.

1. 스프링 부트란?

스프링 부트는 스프링 프레임워크를 기반으로 한 서버측 애플리케이션 개발을 보다 간편하게 해주는 솔루션입니다. 복잡한 XML 설정을 줄이고, ‘Convention over Configuration’ 원칙을 통해 개발자가 비즈니스 로직에 집중할 수 있도록 도와줍니다. 특히, RESTful API 구축과 마이크로서비스 아키텍처에 적합하여 빠른 개발 환경을 제공합니다.

2. 스프링 시큐리티란?

스프링 시큐리티는 스프링 기반 애플리케이션을 위한 인증 및 인가 기능을 제공하는 프레임워크입니다. 유연한 보안 설정과 다양한 인증 방식을 지원하여, 애플리케이션의 보안을 강화하는 데 도움을 줍니다. 비밀번호 암호화, URL 기반 접근 제어, 사용자 역할 및 권한 관리 등의 기능을 제공합니다.

3. 프로젝트 세팅

3.1. 스프링 부트 초기화

스프링 부트 프로젝트를 생성하기 위해, Spring Initializr를 사용합니다. 필요한 의존성(Dependencies)으로는 다음과 같은 것들이 있습니다:

  • Spring Web
  • Spring Security
  • Spring Data JPA
  • H2 Database (또는 MySQL, PostgreSQL 등)
  • Spring Boot DevTools (개발 편의성 향상)

모든 의존성을 추가한 후, ZIP 파일로 프로젝트를 다운로드하고 IDE(예: IntelliJ IDEA, Eclipse)에 임포트합니다.

3.2. 디렉토리 구조 설정

기본 프로젝트 구조는 다음과 같습니다:

    src/
      └── main/
          ├── java/
          │   └── com/
          │       └── example/
          │           └── demo/
          │               ├── controller/
          │               ├── model/
          │               ├── repository/
          │               ├── security/
          │               └── service/
          └── resources/
              ├── application.properties
              └── static/
              └── templates/
    

4. 회원 가입 기능 구현

4.1. 사용자 모델 생성

회원 가입을 위해 사용자 정보를 저장할 User 엔티티 클래스를 생성합니다.

    package com.example.demo.model;

    import javax.persistence.*;
    import java.util.Collection;

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

        private String username;
        private String password;
        
        @ElementCollection(fetch = FetchType.EAGER)
        private Collection roles;

        // Getters and Setters
    }
    

4.2. 레포지토리 인터페이스 작성

데이터베이스와의 상호작용을 위해 레포지토리 인터페이스를 정의합니다.

    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);
    }
    

4.3. 서비스 클래스 작성

유저 정보를 처리하는 서비스 클래스를 구현합니다.

    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 registerUser(User user) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
            userRepository.save(user);
        }

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

4.4. 회원 가입 컨트롤러 구현

회원 가입 요청을 처리할 컨트롤러를 만들어야 합니다.

    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.RequestMapping;

    @Controller
    @RequestMapping("/auth")
    public class AuthController {

        @Autowired
        private UserService userService;

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

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

4.5. 뷰 템플릿 작성

회원 가입을 위한 Thymeleaf 템플릿을 작성합니다.

    <!-- src/main/resources/templates/register.html -->
    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>회원 가입</title>
    </head>
    <body>
        <h1>회원 가입</h1>
        <form action="@{/auth/register}" method="post">
            <label for="username">사용자 이름:</label>
            <input type="text" id="username" name="username" required><br>
            <label for="password">비밀번호:</label>
            <input type="password" id="password" name="password" required><br>
            <button type="submit">가입</button>
        </form>
    </body>
    </html>
    

5. 로그인/로그아웃 기능 구현

5.1. 스프링 시큐리티 설정

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

    package com.example.demo.security;

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    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;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {

        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }

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

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/auth/register", "/auth/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/auth/login")
                .permitAll()
                .and()
                .logout()
                .permitAll();
        }
    }
    

5.2. 로그인 뷰 작성

로그인 페이지를 위한 Thymeleaf 템플릿을 작성합니다.

    <!-- src/main/resources/templates/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">
            <label for="username">사용자 이름:</label>
            <input type="text" id="username" name="username" required><br>
            <label for="password">비밀번호:</label>
            <input type="password" id="password" name="password" required><br>
            <button type="submit">로그인</button>
        </form>
    </body>
    </html>
    

6. 결론

이번 강좌에서는 스프링 부트와 스프링 시큐리티를 사용하여 회원 가입 및 로그인/로그아웃 기능을 구현하는 방법에 대해 알아보았습니다. 기본적인 CRUD 기능과 RESTful API를 이해하고, 보안 기능을 추가하는 확장성 좋은 웹 애플리케이션을 만들 수 있는 기초를 쌓으셨길 바랍니다.

물론, 실전에서는 추가적인 보안 강화와 사용자 경험 향상을 위한 다양한 기능이 필요할 것입니다. 이러한 기능들을 추가하면서 더 심화된 내용을 탐구해 나가시길 바랍니다. 감사합니다!