Spring MVCとSpring Securityによるサーブレット3の非同期サポート

1前書き

このクイックチュートリアルでは、非同期要求に対するServlet 3のサポート、およびSpring MVCとSpring Securityがこれらをどのように処理するかに焦点を当てます** 。

Webアプリケーションの非同期性の最も基本的な動機は、長時間実行される要求を処理することです。ほとんどのユースケースでは、Spring Securityプリンシパルが確実にこれらのスレッドに伝播されるようにする必要があります。

そしてもちろん、Spring Securityリンク:/spring-security-async-principal-propagation[MVCの範囲外で @ Async と統合し、HTTPリクエストを処理する]。

2 Mavenの依存関係

Spring MVCで非同期統合を使用するためには、__pom.xmlに以下の依存関係を含める必要があります。

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>4.2.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>4.2.1.RELEASE</version>
</dependency>

Spring Securityの依存関係の最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.springframework.security%22[here]にあります。

3 Spring MVCと @ Async

docs によると、Spring Security __http://static.springsource.org/spring/docs/current/javadoc-api/org/springframework/web/context/request/async/WebAsyncManager.htmlに統合

最初のステップは、 springSecurityFilterChain が非同期要求を処理するように設定されていることを確認することです。 Servlet configクラスに次の行を追加することで、Java configでそれを行うことができます。

dispatcher.setAsyncSupported(true);

またはXML設定では:

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/** </url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ASYNC</dispatcher>
</filter-mapping>

また、サーブレット設定で async-supported パラメータを有効にする必要があります。

<servlet>
    ...
    <async-supported>true</async-supported>
    ...
</servlet>

これで、 SecurityContext を伝播して非同期要求を送信する準備が整いました。

Spring Securityの内部メカニズムにより、応答が別の Thread でコミットされてユーザーがログアウトしたときに、 SecurityContext がクリアされなくなります。

4ユースケース

簡単な例でこれを実際に見てみましょう。

@Override
public Callable<Boolean> checkIfPrincipalPropagated() {
    Object before
      = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    log.info("Before new thread: " + before);

    return new Callable<Boolean>() {
        public Boolean call() throws Exception {
            Object after
              = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            log.info("New thread: " + after);
            return before == after;
        }
    };
}

Springの SecurityContext が新しいスレッドに伝播されているかどうかをチェックしたい

上記のメソッドは自動的に Callable SecurityContext を含めて実行します。

web - 2017-01-02 10:42:19,011[http-nio-8081-exec-3]INFO
  o.baeldung.web.service.AsyncService - Before new thread:
 [email protected]:
  Username: temporary; Password:[PROTECTED]; Enabled: true;
  AccountNonExpired: true; credentialsNonExpired: true;
  AccountNonLocked: true; Granted Authorities: ROLE__ADMIN

web - 2017-01-02 10:42:19,020[MvcAsync1]INFO
  o.baeldung.web.service.AsyncService - New thread:
 [email protected]:
  Username: temporary; Password:[PROTECTED]; Enabled: true;
  AccountNonExpired: true; credentialsNonExpired: true;
  AccountNonLocked: true; Granted Authorities: ROLE__ADMIN

SecurityContext を伝播するように設定しないと、2番目の要求は null valueになります。

伝播された SecurityContext で非同期リクエストを使用する他の重要なユースケースもあります。

  • 並行して実行できる複数の外部リクエストを作成したい

実行にかなりの時間がかかる場合があります ** 私たちはローカルでそして私たちの外部でやるべきいくつかの重要な処理を持って

リクエストはそれと並行して実行できます。 ** otherは、例えば送信するなどの、忘れ去りシナリオを表します

Eメール

私たちの複数のメソッド呼び出しが以前は同期的にチェーンされていた場合、これらを非同期のアプローチに変換するには結果を同期させる必要があるかもしれません。

5結論

この短いチュートリアルでは、認証されたコンテキストで非同期リクエストを処理するためのSpringサポートを説明しました

プログラミングモデルの観点からすると、新しい機能は一見シンプルに見えます。しかし、もっと深い理解を必要とするいくつかの側面が確かにあります。

この例はMavenプロジェクトhttps://github.com/eugenp/tutorials/tree/master/spring-security-rest[over on Github]としても利用可能です。