[Spring Security] 아키텍처 이해 - 인증 흐름 이해

식빵·2022년 8월 20일
0
post-thumbnail
post-custom-banner

이 시리즈에 나오는 모든 내용은 인프런 인터넷 강의 - 스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 에서 기반된 것입니다. 그리고 여기서 인용되는 PPT 이미지 또한 모두 해당 강의에서 가져왔음을 알립니다.




🥝 그림으로 이해하기


  • 요청이 들어온다.

  • 인증 필터가 요청을 가로채고 다음과 같은 동작을 한다.

    • Authenticaion 객체를 생성하고 ID, PW 정보를 담음
    • AuthenticationManager 에게 Authenticaion 객체와 함께 인증 작업을 위임
  • AuthenticationManager 는 인증필터에서 준 인증객체(Token)에 대한 처리를 해주는
    AuthenticationProvider 를 내부적으로 for 문으로 순회하면서 찾아낸다.
    일종의 중개업자 같은거다. 아무튼 적절한 AuthenticationProvider 를 찾아내면 인증 작업을 위임한다.

  • AuthenticationProvider 에서는 전달받은 인증객체를 UserDetailsService 에게 전달하면서 인증 작업을 또 위임한다.

  • UserDetailsService 는 내부적으로 사용자 정보를 인증객체의 id 정보를 사용해서 가져오고, 만약에 찾지 못하면 예외를 날린다.

  • 만약에 사용자 정보가 조회되면 해당 정보를 UserDetails 타입의 객체에 적절히 담아주고, AuthenticationProvider 에게 반환한다.

  • AuthenticationProvider 에서는 반환받은 UserDetails 타입의 객체에 있는 비밀번호 정보와 사용자 요청으로 받은 비밀번호 정보를 비교해본다. 만약 일치하지 않으면 예외를 던진다.

  • 비밀번호가 일치하면 AuthenticationProvider 는 새로운 인증 객체를 생성하고,
    내부에 UserDetails 타입의 객체와 권한 정보를 담는다.

  • 새로운 인증객체를 필터에서 받아내고, 추후에 필요한 작업에 사용하게 된다.





🥝 코드로 이해하기


생각보다 그렇게 어려운 내용이 아니므로,
그냥 이미지를 나열하고 계속 보여주고 설명은 최소화합니다.


1. 요청 -> AuthenticationFilter


  1. 요청을 가로채서, request 객체에서 username, password 를 추출
  2. 해당 정보로 UsernamePasswordAuthenticaitonToken (인증 객체) 생성
  3. 인증 객체를 AuthenticationManager ( 여기서는 ProviderManager ) 에게 전달하면서
    인증작업을 위임




2. AuthenticationFilter -> AuthenticationManager

참고: ProviderManager classAuthenticationManager interface 의 구현체

  1. 인증필터에게서 받은 인증객체(토큰)을 처리해줄 수 있는 AuthenticaionProvider(이름 그대로 인증 절차 제공자)를 찾아낸다.
  2. 찾게 되면 해당 provider 에게 인증작업을 위임한다.




3. AuthenticationManager -> AuthenticationProvider

참고: DaoAuthenticaionProvider 의 상속 다이어그램



UserDetailsService 에게 사용자 ID 정보를 주면서 사용자 정보 조회 요청
사용자 정보를 조회하는 곳은 DB 일수도 있고, 메모리일 수도 있다.
지금은 특별한 설정이 없어서 메모리를 뒤져본다.




4. AuthenticationProvider -> UserDetailsService

참고: InMemoryUserDetailsManager 의 상속 다이어그램

UserDetailsService 에서는 사용자의 ID 를 통해서 자신이 접근 가능한
repository 에서 사용자 정보를 가져온다. InMemoryUserDetailManager 클래스의
repository 역할을 하는 것은 단순한 Java Map 객체다. 그리고 해당 Map 에서
사용자 id 와 일치하는 키값을 찾아내서 정보를 가져온다.

만약에 사용자를 못찾아서 null 을 반환 받으면,
인증 작업의 실패로 간주하여 예외(UsernameNotFoundException)를 던진다.

이 과정을 예외없이 통과하면 ⭐ID 검증⭐이 완료되는 것이다.

마지막으로 loadByUsername 의 반환형이 UserDetails 인터페이스 타입이니,
그에 맞춰서 UserDetails 인터페이스를 구현한 User 클래스 인스턴스를 반환한다.

참고2: User 클래스




1~4 간단 정리

1. AuthenticationFilter
2. AuthenticationManager ( 토큰 처리 Provider 모색 및 인증 작업 위임 ) 
3. AuthenticationProvider (UserDetailsService 에게 사용자 정보 조회 요청)
4. UserDetailsService (자신의 Repository 에서 사용자 정보 조회 및 UserDetails 타입 객체 반환)

지금까지는 필터부터 시작해서 메소드를 계속 호출하여 프로세스
흐름이 바깥에서 안쪽으로 가고 있었다.

이제부터는 여태 호출한 메소드들의 return 에 의해서 프로세스 흐름이
안쪽에서 바깥쪽으로 가게 된다.




5. AuthenticationProvider <- UserDetailsService

userDetailsService 가 조회한 사용자 정보(UserDetails 타입의 인스턴스)를
반환받고 null 체크를 한다. 이것은 UsersDetailsService 구현이 인터페이스 spec 에 맞는지를 검사하는 것이다. ID 검증 이 아니다!


이후에 retreiveUser 메소드를 통해서 반환받은 사용자 정보에 있는 Password 와
request 를 통해서 날라온 Password 를 비교하게 된다.
매칭이 된다면 무사히 그냥 return 되고, 아니면 예외를 날린다.
이 과정을 통해서 ⭐Password 검증⭐이 완료된 것이다.


위의 ID, Password 검증이 모두 완료되면, 새로운 인증객체를 생성한다.


인증객체 생성 메소드는 위와 같다.
진짜 생성을 하기 전에 비밀번호를 암호화하는 과정을 먼저 거친다.
보안 때문에 그러는 듯하다.


이후에 인증 객체(UsernamePasswordAuthenticaionToken)을 생성한다.
⭐ 이 인증 객체가 AuthenticaionProvider 가 최종적으로 return 하는 값이다 ⭐




6. AuthenticationManager <- AuthenticationProvider

UsernamePasswordAuthenticaionToken(인증 객체)를 반환받은 AuthenticationManager
는 일단 민감한 정볼르 지우기 시작한다 (= eraseCrendentials() 메소드 호출).


민감 정보를 지우는 메소드는 위와 같다. 가볍게 보고 넘어 가겠다.
아무튼, 이 과정을 다 밟은 인증객체는 최종적으로 AuthenticationManager에게 반환된다.




7. AuthenticationFilter <- AuthenticationManager

굳이 설명할 건 없다.
참고로 successfulAuthenticaion 메소드 내에서 session 에 반환받았던
인증 객체를 저장하는 작업을 한다는 것 다시금 기억하기 바란다.

profile
백엔드를 계속 배우고 있는 개발자입니다 😊
post-custom-banner

0개의 댓글