이번 게시글에서는 헷갈리는 개념인 Authentication, Security Context, Security Context Holder, Session를 간단히 정리 해보도록 하겠다.
Authentication 객체는 현재 인증된 사용자의 정보를 담는다. 사용자 이름, 비밀번호, 부여된 권한 등 인증된 사용자에 대한 다양한 정보를 포함한다. 사용자가 로그인을 시도할 때, 스프링 시큐리티는 이 정보를 사용해 인증 과정을 처리한다.
SecurityContext는 현재 보안 상태를 나타내는 객체로, Authentication 객체를 포함한다. 즉, 이 컨텍스트는 현재 인증된 사용자에 대한 정보를 저장한다.
SecurityContextHolder는 SecurityContext를 담는 컨테이너 역할을 하는 정적 클래스다. 애플리케이션의 어디서든 현재 보안 컨텍스트에 접근할 수 있게 해준다. SecurityContextHolder는 ThreadLocal을 사용해 각 스레드마다 SecurityContext의 복사본을 관리하며, 이를 통해 각 요청이 독립적으로 처리되면서도 보안 컨텍스트 정보를 유지한다.
HTTP 세션은 사용자의 상태를 서버에 저장하는 방법이다. 스프링 시큐리티는 사용자가 인증에 성공하면 해당 사용자의 SecurityContext를 HTTP 세션에 저장한다. 이를 통해 사용자가 애플리케이션에 다시 접속하더라도, 이전의 인증 상태를 유지할 수 있다. 요청이 들어올 때마다 스프링 시큐리티는 세션에서 SecurityContext를 로드하여 SecurityContextHolder에 설정한다.
사용자가 인증을 시도하면, 스프링 시큐리티는 Authentication 객체를 생성한다.
생성된 Authentication 객체는 SecurityContext에 저장되며, 이 컨텍스트는 SecurityContextHolder를 통해 현재 스레드에 연결된다.
요청 처리가 완료되면, 변경된 SecurityContext는 다시 HTTP 세션에 저장된다. 사용자가 다시 접속하면 이전 인증 상태를 유지할 수 있다.
사용자가 다음 요청을 할 때, 스프링 시큐리티는 세션에서 SecurityContext를 로드하여 SecurityContextHolder에 설정한다.
SecurityContext를 Session에 저장하는 Filter는 2개중에 하나이다.
Before running the rest of the application, SecurityContextHolderFilter loads the SecurityContext from the SecurityContextRepository and sets it on the SecurityContextHolder.
Next, the application is ran.
둘의 차이는 간단하다.
Unlike, SecurityContextPersistenceFilter, SecurityContextHolderFilter only loads the SecurityContext it does not save the SecurityContext. This means that when using SecurityContextHolderFilter, it is required that the SecurityContext is explicitly saved.
SecurityContextPersistenceFilter 와 SecurityContextHolderFilter를 아래 설정으로 선택할 수 있다.
public SecurityFilterChain filterChain(HttpSecurity http) {
http
// ...
.securityContext((securityContext) -> securityContext
.requireExplicitSave(false or true)
);
return http.build();
}
SecurityContextHolderFilter를 사용한다면 아래와 같이 securityContext를 명시적으로 저장해야함을 잊지말자.
SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);
AbstractAuthenticationProcessingFilter에서도 명시적으로 securityContext를 저장하는 모습을 볼 수 있다.