본문 바로가기
Mechanic: IT 인터넷/Mechanic, M-Tech

Spring Boot Security 커스텀 로그인 구현 - 기본편

by M-LOG : 엠로그 2018. 10. 26.
반응형

원본 작성일: 2018.10.26
보완 작성일: 2026.02.14

Spring Boot Security 커스텀 로그인 구현

Spring Boot에서 Spring Security 커스텀 로그인을 구현했던 기록이다. 원래 2018년에 작성한 글인데, 지금 기준(Spring Boot 3.x)에서 달라진 부분을 함께 정리해둔다.

환경

  • Spring Boot 2.x (원본 기준)
  • Spring Security 5.x
  • JSP + Maven

2026년 기준 참고: Spring Boot 3.x부터 WebSecurityConfigurerAdapter가 삭제됐다. 아래 코드는 2.x 기준이고, 3.x 방식은 글 하단에 별도로 정리한다.

1단계: Security 설정 (WebSecurityConfigurerAdapter)

정적 리소스 제외

@Override
public void configure(WebSecurity web) {
    web.ignoring().antMatchers("/resources/**");
}

CSS, JS, 이미지 같은 정적 파일은 Security 필터를 타지 않도록 제외한다.

HTTP 보안 설정

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/user/loginForm", "/user/registForm", "/main/index")
            .permitAll()
        .anyRequest().denyAll()
    .and()
        .formLogin()
        .loginPage("/user/loginForm")
        .loginProcessingUrl("/user/executeLogin")
        .defaultSuccessUrl("/main/index")
        .usernameParameter("email")
        .passwordParameter("password")
    .and()
        .logout()
        .logoutSuccessUrl("/main/index");
}
설정 역할
permitAll() 비로그인 상태에서도 접근 가능한 URL
denyAll() 매핑되지 않은 URL은 모두 차단
loginPage() 커스텀 로그인 폼 경로
loginProcessingUrl() 로그인 처리 URL (POST)
usernameParameter() 폼에서 아이디로 사용할 필드명

인증 매니저 설정

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userService)
        .passwordEncoder(passwordEncoder());
}

@Bean
public PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

DelegatingPasswordEncoder를 사용하면 {bcrypt}, {noop} 같은 접두사로 인코딩 방식을 자동 판별한다.

2단계: UserDetailsService 구현

@Service
public class UserService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        User user = userRepository.findByEmail(email);
        if (user == null) {
            throw new UsernameNotFoundException(email);
        }
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(user.getUserGroup()));
        return new org.springframework.security.core.userdetails.User(
            user.getEmail(), user.getPassword(), authorities
        );
    }
}

Spring Security가 로그인 시 이 메서드를 호출해서 DB에서 사용자를 조회한다.

회원 등록 시 비밀번호 암호화

@Autowired
private PasswordEncoder passwordEncoder;

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

3단계: 로그인 폼 (JSP)

<form method="POST" action="/user/executeLogin">
    <input type="text" name="email" />
    <input type="password" name="password" />
    <button type="submit">로그인</button>
</form>

주의: name 속성이 Security 설정의 usernameParameter, passwordParameter와 반드시 일치해야 한다.

Spring Boot 3.x에서는?

Spring Boot 3.x(Security 6.x)부터 WebSecurityConfigurerAdapter가 삭제됐다. 대신 SecurityFilterChain을 Bean으로 등록하는 방식을 사용한다.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/user/loginForm", "/user/registForm", "/main/index")
                    .permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/user/loginForm")
                .loginProcessingUrl("/user/executeLogin")
                .defaultSuccessUrl("/main/index")
                .usernameParameter("email")
                .passwordParameter("password")
            )
            .logout(logout -> logout
                .logoutSuccessUrl("/main/index")
            );
        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}

람다 DSL로 바뀌었을 뿐 구조는 거의 동일하다. antMatchersrequestMatchers로 이름이 바뀐 것도 주의.

다음 글: Spring Boot Security (2) - AOP로 사용자 정보 자동 바인딩

반응형