Java/spring

[Spring Security] LoginSuccessHandler와 FailureHandler 호출 원리

yaini 2022. 2. 19. 02:49
반응형

기본적인 인증 책임 구조

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를 사용해서 로직을 구성하려다가 고생했다..🥲

 

반응형