기본적인 인증 책임 구조
SpringSecurity에서 인증은 보통 AuthenticationFilter → AuthenticationManager → AuthenticationProvider 순으로 인증 책임을 위임한다. (UserDetailsService 는 User 정보를 load하는 역할만 수행)
Authentication Success 로직
기본적인 Authentication Filter인 UsernamePasswordAuthenticationFilter 를 보면 AbstractAuthenticationProcessingFilter 를 extends 하는 걸 볼 수 있다.
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (!requiresAuthentication(request, response)) {
chain.doFilter(request, response);
return;
}
try {
Authentication authenticationResult = attemptAuthentication(request, response);
if (authenticationResult == null) {
// return immediately as subclass has indicated that it hasn't completed
return;
}
this.sessionStrategy.onAuthentication(authenticationResult, request, response);
// Authentication success
if (this.continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
successfulAuthentication(request, response, chain, authenticationResult);
}
catch (InternalAuthenticationServiceException failed) {
this.logger.error("An internal error occurred while trying to authenticate the user.", failed);
unsuccessfulAuthentication(request, response, failed);
}
catch (AuthenticationException ex) {
// Authentication failed
unsuccessfulAuthentication(request, response, ex);
}
}
AbstractAuthenticationProcessingFilter 를 보면 attemptAuthentication을 실행 후 Authentication 값이 있으면 ( UsernamePasswordFilter에선 AuthenticationManager의 authenticate 메소드 return 값) successfulAuthentication 를 실행한다.
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authResult);
SecurityContextHolder.setContext(context);
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult));
}
this.rememberMeServices.loginSuccess(request, response, authResult);
if (this.eventPublisher != null) {
this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
this.successHandler.onAuthenticationSuccess(request, response, authResult);
}
successfulAuthentication 메소드는 Filter에 등록된 successHandler를 통해 onAuthenticationSuccess 메소드를 실행하게 된다.
따라서 AbstractAuthenticationProcessingFilter 를 extends 한 Filter에서 Login 로직을 구성해야 Spring Security가 제공하는 AuthenticationSuccessHandler와 AuthenticationFailureHandler 를 사용할 수 있다.
알고보면 되게 당연한 소리인데 다른 Filter를 사용해서 로직을 구성하려다가 고생했다..🥲
'Java > spring' 카테고리의 다른 글
[Spring] WireMock 을 사용한 HTTP Client 유닛테스트 (0) | 2022.12.11 |
---|---|
[Spring] Spring Batch에 Hexagonal Architecture를 적용해보자 (0) | 2022.06.06 |
[Spring] Log4j2를 이용해 로깅해보자 (0) | 2022.05.29 |
[Spring Security] FormLogin에서 Custom Filter 처리 이슈 (0) | 2022.02.21 |
[Spring Cloud] FeignClient Logging 방법 정리 (0) | 2022.02.16 |