참조 포스팅
이번 포스팅에서는 '스프링 시큐리티의 인증/인가 로직'에 대한 내용을 정리했습니다.
기본적으로 스프링 시큐리티는 서블릿 "filter" 를 기반으로 동작하기 때문에 Spring MVC와 분리되어 동작 및 관리됩니다.
🌠 Filter
클라이언트 요청이 DispatcherServlet에 들어가기 전에 거치고 클라이언트로 응답이 전달되기 직전에 거치게 되는 문이라고 생각하면 편합니다.
추가로, 스프링 시큐리티는 세션 기반으로 인증/인가가 이뤄집니다.
🌠 세션 기반 인증
- 클라이언트로부터 로그인 요청 발생합니다. - HttpRequest
- 스프링 시큐리티가 적용된 애플리케이션은 요청이 "Authentication Filter" 를 거칩니다.
- 필터 안에서는 UserDetailsService 구현체를 통해 DB를 조회하여 가입된 회원인지 여부를 확인합니다.
- 가입된 회원이면 UserDetails 객체를 반환하고 session을 생성합니다.
- Spring Security의 in-memory 세션저장소인 SecurityContextHolder에 저장합니다.
- 클라이언트에게 응답 시 생성된 세션의 ID를 함께 브라우저로 보냅니다.
- 브라우저의 JSESSIONID 라는 쿠키에 session ID가 저장되고, 이후에 요청 시마다 JSESSIONID 쿠키 내부의 session ID로 검증하여 Authentication을 제공합니다.
그렇다면, SecurityContextHolder 내부에 어떠한 형태로 저장이 되는지에 대해 의문점이 듭니다.
위 그림은 SecurityContextHolder 내부를 간소화한 그림입니다.
내부 구조
SecurityContextHolder
SecurityContext를 제공하는 정적 메서드(getContext)를 지원합니다.
SecurityContext
서버로 접근하는 클라이언트 주체에 대한 정보와 인증 정보를 담고 있습니다.
Authentication
Principal과 GrantAuthority를 제공합니다. 인증 성공 시, 해당 Authentication이 생성 및 저장됩니다.
Principal
유저 정보이며, UserDetails를 반환합니다.
GrantAuthority
ROLE_XXX 와 같은 유저의 접근 권한을 저장합니다. 권한은 여러개일 수 있기 때문에 Collection 형태로 제공됩니다.
🌠 인증 처리 과정
- HttpRequest가 서버로 들어오면 서블릿 필터인 AuthenticationFilter를 거칩니다.
- UsernamePasswordAuthenticationToken을 생성합니다.
- ProviderManager의 구현체인 AuthenticationManager에게 가입한 유저 여부 검증을 위임합니다.
- AuthenticationManager 내부에는 AuthenticationProvider를 List 형태로 갖고 있습니다.
- Provider가 UserDetailsService로 회원 정보를 가져옵니다.
- Service는 가입된 회원인 경우에 UserDtails 객체를 반환합니다.
- ~ 10. Provider는 반환된 UserDetails 객체를 클라이언트가 제공한 인증정보(UsernamePasswordAuthenticationToken)와 비교한 뒤 사용자의 인증을 처리합니다. 이 후에 SecurityContext에 저장합니다.
마지막으로 Spring Secuirty 설정에 대한 설명으로 마무리하겠습니다.