먼저 (1)에서 사용자가 로그인 폼 등을 이용해 Username(로그인 ID)과 Password를 포함한 request를 Spring Security가 적용된 애플리케이션에 전송합니다.Spring Security에서의 실질적인 인증 처리는 지금부터가 시작입니다.
사용자의 로그인 요청이 Spring Security의 Filter Chain까지 들어오면 여러 Filter들 중에서 UsernamePasswordAuthenticationFilter가 해당 요청을 전달받습니다.
사용자의 로그인 요청을 전달받은 UsernamePasswordAuthenticationFilter는 Username과 Password를 이용해 (2)와 같이 UsernamePasswordAuthenticationToken을 생성합니다.
UsernamePasswordAuthenticationToken은 Authentication 인터페이스를 구현한 구현 클래스이며, 여기에서 Authentication은 ⭐ 아직 인증이 되지 않은 Authentication이라는 사실을 기억하기 바랍니다.
아직 인증되지 않은 Authentication을 가지고 있는 UsernamePasswordAuthenticationFilter는 (3)과 같이 해당 Authentication을 AuthenticationManager에게 전달합니다.즉, ProviderManager가 인증이라는 작업을 총괄하는 실질적인 매니저인 것입니다.레스토랑에서의 매니저(또는 지배인)는 손님에게서 주문받거나 주문받은 음식을 요리한다거나 요리된 음식을 손님에게 가져다주는 등의 구체적인 일을 하지는 않습니다.현실 세계에서의 매니저처럼 Spring Security의 ProviderManager 역시 직접 인증을 처리하는 것이 아니라 인증을 처리할 누군가를 찾은 뒤, 인증 처리를 대신 맡깁니다.
그 누군가가 바로 AuthenticationProvider입니다.
손님의 주문을 받고 요리된 음식을 손님에게 가져다주는 웨이터 또는 웨이트리스, 주문받은 음식을 요리하는 요리사 등이 구체적인 일을 하고, 매니저(또는 지배인) 또는 지배인은 레스토랑에서 일어나는 모든 일들을 총괄해서 관리하는 역할을 합니다.
💡 현실 세계에서의 매니저 또는 지배인이 하는 일을 잠시 떠올려 보세요.
AuthenticationManager는 인증 처리를 총괄하는 매니저 역할을 하는 인터페이스이고, AuthenticationManager를 구현한 구현 클래스가 바로 ProviderManager입니다.
(4)와 같이 ProviderManager로부터 Authentication을 전달받은 AuthenticationProvider는 (5)와 같이 UserDetailsService를 이용해 UserDetails를 조회합니다.그리고 이 UserDetails를 제공하는 컴포넌트가 바로 UserDetailsService입니다.
UserDetails는 데이터베이스 등의 저장소에 저장된 사용자의 Username과 사용자의 자격을 증명해 주는 크리덴셜(Credential)인 Password, 그리고 사용자의 권한 정보를 포함하고 있는 컴포넌트입니다.
UserDetailsService는 (5)에서 처럼 데이터베이스 등의 저장소에서 사용자의 크리덴셜(Credential)을 포함한 사용자의 정보를 조회합니다.
데이터베이스 등의 저장소에서 조회한 사용자의 크리덴셜(Credential)을 포함한 사용자의 정보를 기반으로 (7)과 같이 UserDetails를 생성한 후, 생성된 UserDetails를 다시 AuthenticationProvider에게 전달합니다(8).
UserDetails를 전달받은 AuthenticationProvider는 PasswordEncoder를 이용해 UserDetails에 포함된 암호화된 Password와 인증을 위한 Authentication안에 포함된 Password가 일치하는지 검증합니다.
검증에 성공하면 UserDetails를 이용해 인증된 Authentication을 생성합니다(9).
(2)에서의 Authentication은 인증을 위해 필요한 사용자의 로그인 정보를 가지고 있지만, ⭐ 이 단계에서 ProviderManager에게 전달한 Authentication은 인증에 성공한 사용자의 정보(Principal, Credential, GrantedAuthorities)를 가지고 있다는 사실을 꼭 기억하기 바랍니다.
이제 ProviderManager는 (11)과 같이 인증된 Authentication을 다시 UsernamePasswordAuthenticationFilter에게 전달합니다.
인증된 Authentication을 전달받은 UsernamePasswordAuthenticationFilter는 마지막으로 (12)와 같이 SecurityContextHolder를 이용해 SecurityContext에 인증된 Authentication을 저장합니다. ⭐ 그리고 SecurityContext는 이후에 Spring Security의 세션 정책에 따라서 HttpSession에 저장되어 사용자의 인증 상태를 유지하기도 하고, HttpSession을 생성하지 않고 무상태를 유지하기도 합니다. Spring Security의 세션 정책에 대해서는 JWT 유닛에서 설명하니 조금만 기다려주세요.
핵심 포인트
사용자의 로그인 요청을 처리하는 Spring Security Filter는 UsernamePasswordAuthenticationFilter이다.
UsernamePasswordAuthenticationToken은 Authentication 인터페이스를 구현한 구현 클래스이며, 여기에서 Authentication은 ⭐ **아직 인증이 되지 않은 Authentication**을 의미한다.
AuthenticationManager는 인증 처리를 총괄하는 매니저 역할을 하는 인터페이스이고, AuthenticationManager를 구현한 구현 클래스가 ProviderManager이다.
UserDetails는 데이터베이스 등의 저장소에 저장된 사용자의 Username과 사용자의 자격을 증명해 주는 크리덴셜(Credential)인 Password, 그리고 사용자의 권한 정보를 포함하고 있는 컴포넌트이다.
UserDetails를 제공하는 컴포넌트가 바로 UserDetailsService입니다.
UserDetailsService는 데이터베이스 등의 저장소에서 사용자의 크리덴셜(Credential)을 포함한 사용자의 정보를 조회하여 AuthenticationProvider에게 제공한다.
UsernamePasswordAuthenticationFilter가 생성하는 Authentication은 인증을 위해 필요한 사용자의 로그인 정보를 가지고 있지만, ⭐ AuthenticationProvider가 생성한 Authentication은 인증에 성공한 사용자의 정보(Principal, Credential, GrantedAuthorities)를 가지고 있다.
인증된 Authentication을 전달받은 UsernamePasswordAuthenticationFilter는 SecurityContextHolder를 이용해 SecurityContext에 인증된 Authentication을 저장한다. SecurityContext는 이후에 HttpSession에 저장되어 사용자의 인증 상태를 유지한다.