커스텀 JSON 으로 로그인을 구현하면서 Spring Security에서 제공하는 Form Login에 대해 알아보아겠다고 생각되어 블로그에 정리하고자 합니다.
UsernamePasswordAuthenticationFilter
에 의해 가로채집니다.private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER =
new AntPathRequestMatcher("/login", "POST");
UsernamePasswordAuthenticationToken
객체 생성 후 AuthenticationManager
로 전달authRequest
는 UsernamePasswordAuthenticationToken
으로, 이 토큰은 인증되지 않은 상태로 생성됩니다.this.getAuthenticationManager().authenticate(authRequest)
를 호출하여 AuthenticationManager에게 토큰을 전달하고 인증을 시도합니다.public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
// 유저네임과 패스워드 추출
String username = this.obtainUsername(request);
String password = this.obtainPassword(request);
// username과 password로 인증되지 않은 UsernamePasswordAuthenticationToken 생성
UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username, password);
// 인증 세부 사항 설정 (추가적인 요청 정보 포함)
this.setDetails(request, authRequest);
// AuthenticationManager에게 authRequest 전달하여 인증 진행
return this.getAuthenticationManager().authenticate(authRequest);
}
AuthenticationManager
가 적절한 AuthenticationProvider
를 사용하여 인증 진행AuthenticationManager
는 내부적으로 다양한 AuthenticationProvider
를 사용하여 인증을 처리합니다. 주로 DaoAuthenticationProvider
가 UserDetailsService
를 사용해 데이터베이스에서 사용자 정보를 가져와 비밀번호를 검증하는 방식으로 인증을 처리합니다.@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder()); // PasswordEncoder 설정
return provider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// AuthenticationManager에 DaoAuthenticationProvider 등록
auth.authenticationProvider(daoAuthenticationProvider());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
DaoAuthenticationProvider
에서 인증 처리:DaoAuthenticationProvider
는 UserDetailsService
를 사용해 username에 해당하는 사용자 정보를 데이터베이스나 다른 저장소에서 로드합니다.
DaoAuthenticationProvider는 사용자가 입력한 raw password와 UserDetails에 저장된 암호화된 password를 PasswordEncoder를 사용해 비교합니다.
비밀번호가 일치하면, DaoAuthenticationProvider는 principal로 UserDetails 객체를, authorities로 사용자의 권한 정보를 담은 새로운 UsernamePasswordAuthenticationToken 객체(인증된 상태)를 생성합니다.
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// authentication 객체에서 입력된 username 가져오기
String username = authentication.getName();
// UserDetailsService를 통해 username에 해당하는 사용자 정보 로드
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// 입력된 비밀번호와 데이터베이스에 저장된 비밀번호 비교
if (userDetails == null || !passwordEncoder.matches(authentication.getCredentials().toString(), userDetails.getPassword())) {
throw new BadCredentialsException("Invalid username or password");
}
// 인증 성공: 인증된 UsernamePasswordAuthenticationToken 반환
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
}
ProviderManager
에서 인증 객체 반환:ProviderManager
는 인증된 UsernamePasswordAuthenticationToken
객체를 반환합니다.