이 시리즈에 나오는 모든 내용은 인프런 인터넷 강의 - 스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 에서 기반된 것입니다. 그리고 여기서 인용되는 PPT 이미지 또한 모두 해당 강의에서 가져왔음을 알립니다.
요청이 들어온다.
인증 필터가 요청을 가로채고 다음과 같은 동작을 한다.
AuthenticationManager 는 인증필터에서 준 인증객체(Token)에 대한 처리를 해주는
AuthenticationProvider 를 내부적으로 for 문으로 순회하면서 찾아낸다.
일종의 중개업자 같은거다. 아무튼 적절한 AuthenticationProvider 를 찾아내면 인증 작업을 위임한다.
AuthenticationProvider 에서는 전달받은 인증객체를 UserDetailsService 에게 전달하면서 인증 작업을 또 위임한다.
UserDetailsService 는 내부적으로 사용자 정보를 인증객체의 id 정보를 사용해서 가져오고, 만약에 찾지 못하면 예외를 날린다.
만약에 사용자 정보가 조회되면 해당 정보를 UserDetails 타입의 객체에 적절히 담아주고, AuthenticationProvider 에게 반환한다.
AuthenticationProvider 에서는 반환받은 UserDetails 타입의 객체에 있는 비밀번호 정보와 사용자 요청으로 받은 비밀번호 정보를 비교해본다. 만약 일치하지 않으면 예외를 던진다.
비밀번호가 일치하면 AuthenticationProvider 는 새로운 인증 객체를 생성하고,
내부에 UserDetails 타입의 객체와 권한 정보를 담는다.
새로운 인증객체를 필터에서 받아내고, 추후에 필요한 작업에 사용하게 된다.
생각보다 그렇게 어려운 내용이 아니므로,
그냥 이미지를 나열하고 계속 보여주고 설명은 최소화합니다.
참고:
ProviderManager class
는AuthenticationManager interface
의 구현체
참고:
DaoAuthenticaionProvider
의 상속 다이어그램
UserDetailsService 에게 사용자 ID 정보를 주면서 사용자 정보 조회 요청
사용자 정보를 조회하는 곳은 DB 일수도 있고, 메모리일 수도 있다.
지금은 특별한 설정이 없어서 메모리를 뒤져본다.
참고:
InMemoryUserDetailsManager
의 상속 다이어그램
UserDetailsService 에서는 사용자의 ID 를 통해서 자신이 접근 가능한
repository 에서 사용자 정보를 가져온다. InMemoryUserDetailManager 클래스의
repository 역할을 하는 것은 단순한 Java Map 객체다. 그리고 해당 Map 에서
사용자 id 와 일치하는 키값을 찾아내서 정보를 가져온다.
만약에 사용자를 못찾아서 null 을 반환 받으면,
인증 작업의 실패로 간주하여 예외(UsernameNotFoundException
)를 던진다.
이 과정을 예외없이 통과하면 ⭐ID 검증⭐이 완료되는 것이다.
마지막으로 loadByUsername 의 반환형이 UserDetails 인터페이스 타입이니,
그에 맞춰서 UserDetails 인터페이스를 구현한 User 클래스 인스턴스를 반환한다.
참고2: User 클래스
1. AuthenticationFilter
2. AuthenticationManager ( 토큰 처리 Provider 모색 및 인증 작업 위임 )
3. AuthenticationProvider (UserDetailsService 에게 사용자 정보 조회 요청)
4. UserDetailsService (자신의 Repository 에서 사용자 정보 조회 및 UserDetails 타입 객체 반환)
지금까지는 필터부터 시작해서 메소드를 계속 호출하여 프로세스
흐름이 바깥에서 안쪽으로 가고 있었다.
이제부터는 여태 호출한 메소드들의 return 에 의해서 프로세스 흐름이
안쪽에서 바깥쪽으로 가게 된다.
userDetailsService 가 조회한 사용자 정보(UserDetails 타입의 인스턴스)를
반환받고 null 체크를 한다. 이것은 UsersDetailsService 구현이 인터페이스 spec 에 맞는지를 검사하는 것이다. ID 검증 이 아니다!
이후에 retreiveUser 메소드를 통해서 반환받은 사용자 정보에 있는 Password 와
request 를 통해서 날라온 Password 를 비교하게 된다.
매칭이 된다면 무사히 그냥 return 되고, 아니면 예외를 날린다.
이 과정을 통해서 ⭐Password 검증⭐이 완료된 것이다.
위의 ID, Password 검증이 모두 완료되면, 새로운 인증객체를 생성한다.
인증객체 생성 메소드는 위와 같다.
진짜 생성을 하기 전에 비밀번호를 암호화하는 과정을 먼저 거친다.
보안 때문에 그러는 듯하다.
이후에 인증 객체(UsernamePasswordAuthenticaionToken
)을 생성한다.
⭐ 이 인증 객체가 AuthenticaionProvider 가 최종적으로 return 하는 값이다 ⭐
UsernamePasswordAuthenticaionToken(인증 객체)를 반환받은 AuthenticationManager
는 일단 민감한 정볼르 지우기 시작한다 (= eraseCrendentials()
메소드 호출).
민감 정보를 지우는 메소드는 위와 같다. 가볍게 보고 넘어 가겠다.
아무튼, 이 과정을 다 밟은 인증객체는 최종적으로 AuthenticationManager
에게 반환된다.
굳이 설명할 건 없다.
참고로 successfulAuthenticaion 메소드 내에서 session 에 반환받았던
인증 객체를 저장하는 작업을 한다는 것 다시금 기억하기 바란다.