
DefaultSecurityFilterChain에 기본적으로 등록되는 필터로 세 번째에 위치하는 SecurityContextHolderFilter에 대해 알아보자.
필터가 등록되는 목적은 이전 요청을 통해 이미 인증한 사용자 정보를 현재 요청의 SecurityContextHolder의 SecurityContext에 할당하는 역할을 수행하고, 현재 요청이 끝나면 다른 스레드가 사용할 수 있도록 SecurityContext를 초기화한다.
세션 방식에서 주로 사용된다.
커스텀 SecurityFilterChain을 생성해도 등록되며, 원한다면 아래 구문을 통해 비활성화 시킬 수 있다.
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .securityContext((context) -> context.disable()); return http.build(); }JWT 방식을 사용한다 하더라도, 마지막에 SecurityContext를 초기화시켜주는 부분이 있기 때문에 웬만하면 disable하지 않도록 한다.

이전 요청에서 사용자가 로그인을 했고 STATELESS 상태가 아니라면, 서버의 세션(메모리) 또는 레디스와 같은 저장 매체에 유저의 정보가 있을 것이다.
해당 저장 매체로 부터 유저 정보를 가져올 때, SecurityContextRepository라는 인터페이스의 loadDefferdContext() 메소드를 활용해서 불러온다.
(만약 존재하지 않는 경우 빈 객체를 응답한다.)
이후 불러온 유저 정보를 SecurityContextHolder에 setDefferdContext() 메소드를 통해 저장하고 다음 필터로 넘긴다.
응답이 이루어지면 try의 finally 구문을 통해 SecurityContextHolder의 유저 정보를 제거한다.
저장 매체로 부터 유저 정보를 가져오는 부분은 SecurityContextRepository 인터페이스를 구현한 클래스에게 맡기고, 불러온 유저 정보도 SecurityContextHolder에 설정한다.
유저 정보를 불러오는 SecurityContextRepository가 인터페이스로 정의된 이유는 세션, 레디스, 기타 매체별로 구현 방식이 다르기 때문이다.
HttpSessionSecurityContextRepository: 서버 세션 기반 구현체 (기본적으로 등록되는 구현체)NullSecurityContextRepository: 아무 작업을 하지 않을때 (JWT를 사용해서 STATELESS 관리시)RequestAttributeSecurityContextRepository: HTTP request 저장 기반 구현체SecurityContextPersistenceFilter와 SecurityContextHolderFilter의 차이
자료를 찾다보면 비슷한 역할을 수행하는
SecurityContextPersistenceFilter도 확인할 수 있다.SecurityContextHolderFilter가SecurityContextPersistenceFilter의 후속으로 시큐리티 5.8 버전 부터 내부 구현이 변경되면서 기존 클래스는 deprecated 되었다.
- 변경된 부분
구현들이 많이 변경되었지만 기능은 거의 동일하다. 다만 주의 깊게 볼 부분은 try문에서 finally에 존재하는 doFilter 응답 부분에 대해서 변경점 저장 로직이다.
SecurityContextPersistenceFilterfinally { SecurityContext contextAfterChainExecution = this.securityContextHolderStrategy.getContext(); // Crucial removal of SecurityContextHolder contents before anything else. this.securityContextHolderStrategy.clearContext(); this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse()); request.removeAttribute(FILTER_APPLIED); this.logger.debug("Cleared SecurityContextHolder to complete request"); }
SecurityContextHolderFilterfinally { this.securityContextHolderStrategy.clearContext(); request.removeAttribute(FILTER_APPLIED); }
- 쟁점
이전 클래스는 SecurityContext가 변경되면 변경된 부분을 세션이나 레디스와 같은 저장소에 SecurityContextRepository로 저장했지만 현재 클래스는 변경점을 저장하지 않는다.
따라서 필요하다면 직접 해당 부분을 불러와 커스텀을 진행해주어야 한다.