SecurityContextHolderFilter의 목적
이 필터는 DefaultSecurityFilterChain에 기본적으로 등록되는 필터 중 세 번째에 위치하는 필터이다.
해당 필터는 주로 세션 방식을 통한 인증 처리에 사용된다.
수행하는 기능은 이전 요청을 통해서 이미 인증된 사용자 정보라면, SecurityContext에 할당하고 요청이 끝나면
SecurityContext를 초기화 한다.
만약 해당 필터의 비활성화를 원한다면, 아래와 같이 설정하면 된다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.securityContext((context) -> context.disable());
return http.build();
}
하지만, 굳이 비활성화할 필요가 없다.
마지막에 SecurityContext를 초기화하는 로직이 있기에 세션 방식을 사용한다면, 중요한 로직이며 jwt와 같은 다른 인증 방식을 선택하여도 비활성화 하지 않는 것이 좋다.
SecurityContextHolderFilter의 구성
사용자가 이전 요청을 통해 로그인을 한 경우, 사용자 정보를 stateless( ex. JWT )한 방식으로 저장하는 것이 아니라면 서버의 세션이나 레디스와 같은 저장 공간에 정보가 담겨 있을 것이다.
그리고 이 저장 공간으로 유저 정보를 가져온다면, SecurityContextRepository 인터페이스를 통해 정보를 받아온다.
여기서 SecurityContextRepository는 다양한 저장 구현체를 통해 정보를 불어올 수 있기에 인터페이스로 정의되었으며,
안에서 정의한 loadDefferdContext() 메소드를 활용한다.
SecurityContextHolderFilter의 동작
먼저, 클라이언트의 request에 따라 SecurityContextHolderFilter가 동작하며
SecurityContextRepository를 통해 HttpSession을 확인한다.
만약, SecurityContext에 정보가 존재하지 않는다면, 새로운 SecurityContext를 생성하여
AuthenticationFilter를 통한 인증을 거쳐 생성된 객체를 SecurityContext에 저장한다.
한편 SecurityContext가 존재한다면 해당 객체를 가져와서 다음 필터에 전달한다.
그리고 응답의 흐름에서 사용자에게 전달하기 이전에 SecurityContext를 삭제 처리한다.
( 스레드를 다시 스레드 풀에 넘겨야 하는데, 해당 사용자의 정보를 기억하고 있으면 안된다. )
SecurityContextRepository 기본 구현체와 등록 방법
위에서 봤던 것처럼 SecurityContextRepository 인터페이스를 통해 다양한 저장 방법으로부터
사용자의 정보를 저장하는 경우, 정보를 불러올 수 있도록 기능한다고 파악하였다.
구현체 종류
그리고 기본적으로 제공해주는 구현체들에는 아래와 같은 것들이 있다.
✅ HttpSessionSecurityContextRepository : 서버 세션 기반 구현체
✅ NullSecurityContextRepository : 아무 작업을 하지 않을때 (JWT를 사용해서 STATELESS 관리시)
✅ RequestAttributeSecurityContextRepository : HTTP request 저장 기반
✅ 구현체기타 : 직접 구현해서 사용하면 된다.
등록 방법
기본 구현체들은 아래와 같은 방법을 통해 등록할 수 있다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.securityContext((context) -> context
.securityContextRepository(new RequestAttributeSecurityContextRepository()));
return http.build();
}
SecurityContextHolderFilter와 SecurityContextPersistenceFilter 차이
SecurityContextHodlerFilter 이전에 SecurityContextPersistenceFilter가 있었는 데, 이는 현재
deprecated된 필터로 레거시에 속한다.
그리고 현재 필터에서 로직 상 변경된 부분 중 신경써야 할 부분은 아래와 같다.
먼저, SecurityContextPersistenceFilter의 일부 코드이다.
finally {
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");
}
코드를 보면 saveContext() 메소드를 호출하는 로직이 있다.
이는 변경된 SecurityContext의 상태를 저장해주는 것이다.
반면, SecurityContextHolderFilter의 코드는 아래와 같다.
finally {
this.securityContextHolderStrategy.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
이전 버젼과 달리 변경된 정보를 save하는 로직이 없다.
따라서 만약, 특정 로직 수행에 있어서 유저 정보의 변환과 같이 변경 지점이 있고 이를 SecurityContext에
저장이 필요한 것이라면, SecurityContextPersistenceFilter에서 기존에 수행하던 save와 같이 로직을 커스텀 해주어야한다.
'Spring > 시큐리티 기본원리' 카테고리의 다른 글
시큐리티 기본 원리( 12 ) - CorsFilter (2) | 2025.01.24 |
---|---|
시큐리티 기본 원리( 11 ) - HeaderWriterFilter (0) | 2025.01.23 |
시큐리티 기본 원리( 9 ) - WebAsyncManagerIntegrationFilter (0) | 2025.01.23 |
시큐리티 기본 원리( 8 ) - DisableEncodeUrlFilter (0) | 2025.01.20 |
시큐리티 기본 원리( 7 ) - GenericFilterBean과 OncePerRequestFilter 차이 (0) | 2025.01.20 |
댓글