스프링 시큐리티 - 로그인과정2 - AuthenticationManager

HUSII·2023년 8월 23일
0

스프링 시큐리티

목록 보기
6/7

스프링 시큐리티 공식 문서를 읽고, 라이브러리 코드들을 뜯어보면서 공부했습니다.
인증은 username/password 인증을 기준으로 설명하겠습니다.

이전 장에서, UsernamePasswordAuthenticationFilterBasicAuthenticationFilter가 HttpServletRequest로부터 username/password를 받아서 UsernamePasswordAuthenticationToken을 생성하는 과정을 알아봤습니다.

그리고 두 필터 모두 AuthenticationManager의 authenticate 메서드를 호출하는 것으로 이전 장을 마무리했습니다.

authenticate 메서드를 호출할 때, UsernamePasswordAuthenticationToken을 보냅니다.

이번 장에서 AuthenticationManager가 어떻게 토큰을 인증하는지 알아보겠습니다.


AuthenticationManger의 authenticate 메서드

AuthenticationManager는 interface입니다.

스프링 시큐리티에서 다른 설정을 하지 않았다면 기본적으로 ProviderManager가 구현 객체로 주입됩니다.

ProviderManager는 authenticate 메서드의 인자로 받은 Authentication 객체의 인증을 할 수 있는 AuthenticationProvider을 찾기 시작합니다.

AuthenticationProvider는 interface입니다.
AuthenticationProvider의 구현 객체들이 ProviderManager에 등록되어 있습니다.


ProviderManager의 authenticate 실제 코드

(위 코드는 ProviderManager의 authenticate 메서드의 일부 코드를 캡쳐한 사진입니다.)

  1. 173번 코드를 보면 여러 provider들을 for문을 통해 탐색하고 있습니다.

  2. 174번 코드는 해당 provider가 현재 받은 Authentication 객체를 인증할 수 있는지 검증하는 코드입니다.
    Class<? extends Authentication> toTest = authentication.getClass();
    해당 provider가 현재 받은 Authentication 객체를 인증할 수 없다면 다음 provider를 탐색합니다.

  3. 182번 코드를 보면, 해당 provider는 현재 받은 Authentication 객체를 인증할 수 있기 때문에, authentication을 인자로 보내면서 provider의 authenticate 메소드를 호출합니다.


DaoAuthenticationProvider의 authenticate 메서드

여기서 UsernamePasswordAuthenticationToken의 인증을 진행할 수 있는 AuthenticationProvider의 구현 객체는 DaoAuthenticationProvider 입니다.

따라서 ProviderManager로부터 DaoAuthenticationProvider의 authenticate 메서드가 호출됩니다.

그리고 DaoAuthenticationProvider는 인증하는 중간에 UserDetailsServiceloadUserByUsername 메서드를 호출합니다.

loadUserByUsername 메서드를 통해 입력받은 username에 해당하는 사용자가 DB에 있는지 조회합니다.

없다면 Exception 호출합니다.

username에 해당하는 사용자가 DB에 있다면, DaoAuthenticationProvider는 해당 사용자 이름과 password를 비교해서 인증을 진행합니다.

인증에 성공하면 DaoAuthenticationProvider가 Authentication 객체를 ProviderManager로 반환합니다.
그리고 ProviderManager도 Authentication 객체를 AuthenticationFilter에게 반환합니다.

마지막으로 AuthenticationFilter가 ProviderManager(AuthenticationManager의 구현 객체)로부터 받은 Authentication을 SecurityContextHolder에 저장합니다.


전체 과정

아래 두개의 그림은, 인터페이스에 구현객체가 주입되는 과정과 전체 로그인 과정에 대한 그림입니다.

(Form 로그인 기준) UsernamePasswordAuthenticationFilter가 사용되었습니다.

  1. UsernamePasswordAuthenticationFilterUsernamePasswordAuthenticationToken 객체의 인증을 위해, AuthenticationManger의 authenticate 메서드를 호출합니다.

    여기서 AuthenticationManager의 구현 객체인 ProviderManager의 authenticate 메서드가 실행됩니다.

  2. ProviderManager는 현재 받은 토큰을 인증할 수 있는 Provider를 탐색합니다.

    UsernamePasswordAuthenticationToken을 인증할 수 있는 Provider는 AuthenticationProvider이기 때문에, AuthenticationProvider의 authenticate 메서드를 호출합니다.

    여기서 AuthenticationProvider의 구현 객체인 DaoAuthenticationProvider의 authenticate 메서드가 실행됩니다.

  3. DaoAuthenticationProvider는 입력받은 토큰으로부터, username이 현재 DB에 있는지 조회하기 위해, UserDetailsServiceloadUserByUsername 메서드를 호출합니다.

  4. UserDetailsService는 입력받은 username을 DB에 조회합니다.

  5. 해당 유저가 있다면 유저 정보를 반환합니다.

    없다면 예외가 발생합니다. (UsernameNotFoundException)

    (성공기준) DaoAuthenticationProviderUserDetailsService로 부터 받은 유저정보의 password와 UsernamePasswordAuthenticationToken의 password를 비교합니다.

  6. password가 같다면(인증 성공), DaoAuthenticationProvider는 성공된 토큰을 ProviderManager에게 반환합니다. (DaoAuthenticationProvider의 authenticate 메서드 종료)

  7. ProviderManager는 받은 토큰을 UsernamePasswordAuthenticationFilter에게 반환합니다. (ProviderManager의 authenticate 메서드 종료)

  8. UsernamePasswordAuthenticationFilter은 받은 토큰(UsernamePasswordAuthenticationToken)을 SecurityContextHolder에 저장합니다.

다음 장에서, AnonymousAuthenticationFilterExceptionTranslationFilter가 하는 역할에 대해 알아보겠습니다.

개인적으로 공부한 내용을 정리한 글입니다.
지적, 피드백 환영합니다.

profile
공부하다가 생긴 궁금한 것들을 정리하는 공간

0개의 댓글