이 글에서는 WebFilter를 구현하면서 겪었던 잘못된 사용에 대해 다루고자 합니다.

문제 상황

Spring Cloud Gateway에 JWT 인증 필터를 구현하였다.

위와 같이 @Value 값을 주입받기 위해, WebFilter를 구현하고 @Component 어노테이션을 붙여서 Bean에 등록했다.

그리고 Security FilterChain에 구현한 Filter를 추가했다. 필터 우선순위도 넣어줬다.

자연스러운 흐름이겠지만, 이것은 잘못된 사용이다. 왜냐하면, 디버그 모드로 찍어보면 필터를 두 번 검사하게 될 것이다.

문제 원인

https://docs.spring.io/spring-boot/reference/web/reactive.html#web.reactive.webflux.web-filters 문서를 참고해보면

WebFilter beans found in the application context will be automatically used to filter each exchange.

라고 나와있다. 즉, WebFilter가 Bean에 등록되면 application context에 자동으로 filter가 사용된다는 것이다.
따라서 위 문제 상황의 경우, @Component로 Bean으로 등록했으니 이미 필터가 수행되는데, 이를 또 SecurityFilterChain에서 등록하니 결과적으로 두 번 필터를 수행하는 것.

DefaultServerWebExchange와 SecurityContextServerWebExchange

  1. DefaultServerWebExchange
    • Spring WebFlux의 기본적인 요청 처리 흐름을 담당한다. 이 Exchange 객체는 HTTP 요청과 응답을 처리하는 데 사용된다. 이때 WebFilter는 HTTP 요청을 가로채서 처리할 수 있도록 DefaultServerWebExchange에서 필터 리스트에 추가된다. 즉, 모든 HTTP 요청에 대해 WebFilter가 자동으로 실행되는 구조이다.
  2. SecurityContextServerWebExchange:
    • Spring Security가 추가된 경우, 기본 DefaultServerWebExchange 객체를 감싸는 SecurityContextServerWebExchange가 사용된다. 이 객체는 보안 관련 작업(인증/인가)을 추가로 처리하는 역할을 한다.
    • SecurityContextServerWebExchange도 기본적으로 DefaultServerWebExchange와 동일하게 WebFilter를 처리할 수 있도록 설정된다. 그러나 여기서 문제는 Security 설정에서 이미 WebFilter를 등록했을 경우이다. 이렇게 되면 Spring WebFlux에서 한 번 필터링을 수행한 후, Spring Security에서 또 한 번 필터링을 수행하는 구조가 만들어져 필터가 두 번 실행되는 것이다.

문제 해결: FilterChain에서 빼고 순서를 위해 @Order를 사용하거나, @Bean에 등록하지 말거나

@Order 어노테이션을 사용해서 적당히 1의 수를 넣었다. (default 값은 INTEGER.MAX_VALUE로, 값이 클수록 우선순위가 낮음)

그리고 Filterchain에는 이 필터 등록을 지웠다.

참조