Spring WebFlux で Spring Security と CORS WebFilter を併せて使う

概要

Spring WebFlux を使う際に、CORS を有効にする方法と認証/認可を有効にする方法を下記の記事で説明しました。しかし、この 2 つの内容を併せて適用すると、CORS が期待通りに機能しません。原因は、WebFilter の実行順にあります。この記事では、WebFilter の並び順を制御して、これらを併せて使う方法について説明します。

nosix.hatenablog.com

nosix.hatenablog.com

目次

確認環境

  • Spring Boot 2.0.3.RELEASE
  • Kotlin 1.2.50

参考情報

解説

問題

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 {
    // ...
}