CORSプリフライトとSpring Securityで401を修正

1. 概要

この短いチュートリアルでは、クロスオリジン通信をサポートし、Spring Securityを使用するアプリケーションで発生する可能性のある「プリフライトの応答に無効なHTTPステータスコード401」というエラーを解決する方法を学習します。
最初に、クロスオリジンリクエストとは何かを確認し、次に問題のある例を修正します。

2. クロスオリジンリクエスト

要するに、クロスオリジンリクエストは、リクエストのオリジンとターゲットが異なるHTTPリクエストです。 たとえば、あるドメインからWebアプリケーションが提供され、ブラウザが別のドメインのサーバーにAJAXリクエストを送信する場合がこれに該当します。
クロスオリジンリクエストを管理するには、サーバーはCORSまたはクロスオリジンリソース共有と呼ばれる特定のメカニズムを有効にする必要があります。
CORSの最初のステップは、リクエストのターゲットがそれをサポートしているかどうかを判断する_OPTIONS_リクエストです。 *これはプリフライトリクエストと呼ばれます。*
サーバーは、プリフライトリクエストにヘッダーのコレクションで応答できます。
  • * _Access-Control-Allow-Origin _:アクセスできる起点を定義します
    リソースに。 「
    」は任意の起源を表します

  • * _Access-Control-Allow-Methods _:*許可されたHTTPメソッドを示します
    クロスオリジンリクエスト用

  • * _Access-Control-Allow-Headers _:*許可されたリクエストを示します
    クロスオリジンリクエストのヘッダー

  • * _Access-Control-Max-Age _:*結果の有効期限を定義します
    キャッシュされたプリフライトリクエストの

    そのため、プリフライトリクエストがこれらの応答ヘッダーから決定された条件を満たしていない場合、実際のフォローアップリクエストは、クロスオリジンリクエストに関連するエラーをスローします。
  • https://www.baeldung.com/spring-cors [Spring-poweredサービスにCORSサポートを追加]は簡単ですが、正しく構成されていないと、このプリフライトリクエストは常に401で失敗します。*

3. CORS対応のREST APIの作成

問題をシミュレートするために、最初にクロスオリジンリクエストをサポートする簡単なREST APIを作成しましょう。
@RestController
@CrossOrigin("http://localhost:4200")
public class ResourceController {

    @GetMapping("/user")
    public String user(Principal principal) {
        return principal.getName();
    }
}
_ @ CrossOrigin_アノテーションは、引数に記載されているオリジンからのみAPIにアクセスできるようにします。

4. REST APIを保護する

Spring SecurityでREST APIを保護しましょう:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .httpBasic();
    }
}
この構成クラスでは、すべての着信要求に承認を適用しました。 その結果、有効な認証トークンなしですべてのリクエストが拒否されます。

5. プリフライトリクエストを行う

REST APIを作成したので、_curl_を使用してプリフライトリクエストを試してみましょう。
curl -v -H "Access-Control-Request-Method: GET" -H "Origin: http://localhost:4200"
  -X OPTIONS http://localhost:8080/user
...
< HTTP/1.1 401
...
< WWW-Authenticate: Basic realm="Realm"
...
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Access-Control-Allow-Origin: http://localhost:4200
< Access-Control-Allow-Methods: POST
< Access-Control-Allow-Credentials: true
< Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
...
このコマンドの出力から、* 401で要求が拒否されたことがわかります*。
これは_curl_コマンドであるため、出力に「プリフライトの応答に無効なHTTPステータスコード401」というエラーは表示されません。
ただし、別のドメインからREST APIを使用するフロントエンドアプリケーションを作成し、ブラウザーで実行することで、この正確なエラーを再現できます。

6. ソリューション

  • Spring Securityの設定では、プリフライトリクエストを承認から明示的に除外していません*。 Spring Securityはデフォルトでall endpointsを保護することに注意してください。

    その結果、* APIはOPTIONSリクエストにも認証トークンを必要とします。*
    Springは、OPTIONSリクエストを認可チェックから除外するためのすぐに使えるソリューションを提供します:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // ...
        http.cors();
    }
}
_cors()_メソッドは、Springが提供する_CorsFilter_をアプリケーションコンテキストに追加し、OPTIONS要求の承認チェックをバイパスします。
これで、アプリケーションを再度テストして、機能することを確認できます。

7. 結論

この短い記事では、Spring Securityおよびクロスオリジンリクエストにリンクされている「プリフライトのレスポンスに無効なHTTPステータスコード401」というエラーを修正する方法を学びました。
*この例では、クライアントとAPIを異なるドメインまたはポートで実行して問題を再現する必要があることに注意してください。*たとえば、実行時にデフォルトのホスト名をクライアントに、マシンのIPアドレスをREST APIにマップできます。ローカルマシン。
いつものように、このチュートリアルに示されている例はhttps://github.com/eugenp/tutorials/tree/master/spring-security-cors[Github上]にあります。