본문 바로가기

Tech/Spring

Spring Security 인증 절차 & 핵심 인터페이스

개요

 이 포스팅을 통해 스프링 시큐리티 인증 처리의 핵심 인터페이스와 메서드들을 살펴보고, 메서드 호출 순서를 따라가면서 인증 처리의 동작 순서를 살펴보고자 합니다. 각 인터페이스의 핵심 메서드와 수행 로직을 표로 추출해 보았습니다.

 

Spring Security 기본 제공 로그인 흐름

  1. AbstractAuthenticationProcessingFilter의 attemptAuthentication 메서드가 호출된다.
  2. 폼에 입력된 username과 password를 각각 UsernamePasswordAuthenticationToken의 principal과 credential에 담아 생성한다. (인증처리 전의 토큰이라고 하겠다.)
  3. AuthenticationManager의 authenticate 메서드를 호출해 파라미터로 UsernamePasswordAuthenticationToken을 넘겨준다.
  4. AuthenticationManager의 구현체인 ProviderManager는 다음을 수행한다.
    1. ProviderManager는 AuthenticationProvider 객체들을 여러개 갖고 있다.
    2. UsernamePasswordAuthenticationToken을 검증할 수 있는 Provider를 찾아 인증 처리를 맡긴다.
  5. AuthenticationProvider의 authenticate 메서드가 호출된다.
  6. UsernamePasswordAuthenticationToken에서 username(principal)을 꺼내 UserDetailsService의 loadUserByUsername 메서드를 호출하고, UserDetails 인터페이스를 구현한 User 객체를 리턴한다.
  7. AuthetnicationProvider에서는 반환된 UserDetails를 새로운 UsernamePasswordAuthenticationToken의 principal로 담는다. (인증처리가 완료된 토큰이라고 하겠다.)
  8. 인증처리가 완료되어 새롭게 생성된 UsernamePasswordAuthenticationToken이 반환된다.
  9. 최종적으로 토큰은 AbstractAuthenticationProcessingFilter에게로 리턴되고, 필터의 successfulAuthentication 메서드가 호출된다.
  10. successfulAuthentication 메서드 내부에서 다음을 수행한다. 
    1. SecurityContext에 Authentication(인증처리가 완료된 토큰)이 담긴다.
    2. SecurityContextHolder에 SecurityContext가 담긴다.
    3. 이제 사용자의 요청이 스프링부트 애플리케이션에서 처리되는 동안 인증된 객체(Authentication)에 전역적으로 접근할 수 있게 된다.

 

1. UsernamePasswordAuthenticationFilter

핵심 메서드 책임
attemptAuthentication Authentication(인증처리 전의 토큰)을 생성하고 인증처리를 AuthenticationManager에게 위임한다.
successfulAuthentication 인증처리가 성공적으로 완료되면 호출되는 메서드로, 인증 성공 후처리를 한다.
unsuccessfulAuthentication 인증처리가 실패하면 호출되는 메서드로, 인증 실패 후처리를 한다.

AbstractAuthenticationFilter

AbstractAuthenticationFilter 추상클래스의 메서드 doFilter 내부에서 attemptAuthentication 메서드를 호출합니다.

 

UsernameAuthenticationFilter

UsernamePasswordAuthenticationFilter는 AbstractAuthenticationFilter 추상클래스를 구현했습니다. 이 필터는 인증처리 전의 토큰을 생성하고 AuthenticationManager에게 인증 처리를 위임합니다.

 

2. ProviderManager

핵심 메서드 책임
authenticate AuthenticationProvider 목록을 순회하며 인증처리를 맡길 수 있는 Provider에게 인증처리를 위임한다.

ProviderManager

ProviderManager는 AuthenticationManager 인터페이스를 구현한 구현체입니다. 매니저라는 이름답게 Provider 객체 목록 providers 를 갖고 있습니다. 그렇다면, UsernamePasswordAuthenticationFilter가 호출했던 메서드 authenticate가 오버라이드 된 것을 보겠습니다.

 

ProviderManager

providers를 순회하는 iterator를 통해 AuthenticationProvider 하나하나를 살펴봅니다. Filter가 ProviderManager 에게 인증처리를 위임하며 함께 넘겨준 토큰(Authentication)에 대해 Provider가 인증처리를 수행할 수 있는지 supports 메서드로 확인합니다. 가능하다면, 해당 Provider에게 또 다시 인증처리를 위임합니다.

 

3. DaoAuthenticationProvider

핵심 메서드 책임
authenticate retrieveUser 메서드를 호출해 인증처리를 진행하고, 성공 시 인증이 완료된 AuthenticationToken을 새롭게 생성하여 리턴한다.
retrieveUser 파라미터로 주어진 Authentication 토큰에서 username을 추출하고, UserDetailsService의 loadUserByUsername 메서드 호출을 통해 UserDetails를 리턴한다.

AbstractUserDetailsAuthenticationProvider

AbstractUserDetailsAuthenticationFilter에서는 retrieveUser를 호출해 UserDetails를 반환 받아 인증을 완료합니다.

 

DaoAuthenticationProvider

스프링 시큐리티는 UsernamePassword 폼로그인 기본 설정을 따를 경우, DaoAuthenticationProvider를 사용합니다. retrieveUser에서는 UserDetailsService의 loadUserByUsername을 호출해 UserDetails 객체를 리턴합니다.

 

AbstractUserDetailsAuthenticationProvider

AbstractUserDetailsAuthenticationProvider는 인증처리가 완료된 토큰을 새롭게 생성하는 메서드를 호출합니다.

 

4. UsernamePasswordAuthenticationToken

UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken
AbstractAuthenticationToken

토큰의 인증처리를 완료한다는 것이 거창한 건 아니고, AbstractAuthenticationToken의 authenticated 필드를 true로 바꿔준다는 의미입니다.

 

5. 다시 AbstractAuthenticationFilter

AbstractAuthenticationFilter

1번의 attemptAuthentication 메서드 호출이 완료되면 2번 successfulAuthentication 메서드를 호출합니다.

 

UsernamePasswordAuthenticationFilter

스프링 애플리케이션 코드 전체에서 전역적으로 접근이 가능한 SecurityContextHolder에 인증처리가 완료된 Authentication 토큰을 SecurityContext에 담아 저장합니다. 이후 AuthenticationSuccessHandler가 있다면, onAuthenticationSuccess 메서드를 호출해 성공 후처리를 진행합니다.

 

Reference