概要
Spring WebFlux を使う際に、CORS を有効にする方法と認証/認可を有効にする方法を下記の記事で説明しました。しかし、この 2 つの内容を併せて適用すると、CORS が期待通りに機能しません。原因は、WebFilter の実行順にあります。この記事では、WebFilter の並び順を制御して、これらを併せて使う方法について説明します。
目次
確認環境
- Spring Boot 2.0.3.RELEASE
- Kotlin 1.2.50
参考情報
- WebFluxにおけるFilter · matsumanaの技術メモ
- @Component と @Order で Order を指定する方法
- java - Filter order in spring-boot - Stack Overflow
- FilterRegistrationBean を使って springSecurityFilterChain の Order を指定する方法
解説
問題
CorsFilter は SecurityWebFilterChain よりも前に適用される必要があります。CorsFilter には @Component を付けているため、@Order を付けて適用順を指定できます。@Bean にも @Order を付けることで適用順を指定できますが、@Bean が付けられた securityFilterChain メソッドに @Order を付けても期待通りの順番になりません。
FilterRegistrationBean を使うことで順番を指定する方法もあります。しかし、この方法では javax.servlet.Filter を参照します。WebFlux を使う場合には Servlet を使いません。そのため、WebFlux を使う場合には javax.servlet.Filter を参照できず、FilterRegistrationBean を使った順番の指定はできません。
2 つの WebFilter の適用順をどのように指定すればよいのでしょう?
調査
WebFilter の並び順を決定している部分をデバッガで追いました。並び替えているコードは、DefaultListableBeanFactory.java#L1204 です。さらに動きを追っていくと、OrderComparator.java で並び順を決めていることがわかります。
さらに、OrderComparator が CorsFilter と SecurityWebFilterChain を比較している動作を調べると、WebFluxSecurityConfiguration クラスの springSecurityWebFilterChainFilter メソッドで生成された Bean の Order が -100 に設定されていることが分かります。WebFluxSecurityConfiguration.java を読むと確かに Order が -100 に設定されています。
また、WebFluxSecurityConfiguration.java を読むと、SecurityWebFilterChain が WebFilterChainProxy に包含されていることが分かります。SecurityWebFilterChain を生成するメソッドに @Order を付けても無駄な理由はこれでした。
解決方法
WebFilterChainProxy Bean の Order が -100 になっていますので、CorsFilter Bean の Order を -100 よりも小さくすれば CorsFilter が先に適用されます。
@Component @Order(-200) class CorsFilter : WebFilter { // ... }