質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.22%

ログイン処理後のリクエストのプレフライトでHTTPエラー403が返ってきてしまいます。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,428

nerianighthawk

score 144

 前提・実現したいこと

サーバサイド: Spring Boot
フロントエンド: Angular5
CORSを使って、ログイン後のリクエストのフィルタリングを行おうとしています。
ログイン処理は完了しており、サーバサイドで発行されたトークンをリクエストヘッダに張り付けてリクエストを行おうとしています。
その際、以下の通りエラーが発生してしまいました。解決方法をご教授よろしくお願いします。

 発生している問題・エラーメッセージ

リクエストヘッダに
content-type: application/json
x-xsrf-token: [サーバサイドで発行されたトークン]
を加えて送っているため、プレフライトが実行されます。
その際、以下のようなエラーになります。

Failed to load http://localhost:8080/v1/templates: Response for preflight has invalid HTTP status code 403.


実際のHttpヘッダ

 該当のソースコード

以下が SecurityConfig のソースです。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        RequestMatcher csrfRequestMatcher = new RequestMatcher() {
            // CSRFのチェックをしないURL
            private AntPathRequestMatcher[] requestMatchers = {
                    new AntPathRequestMatcher("/v1/login/**")
            };

            @Override
            public boolean matches(HttpServletRequest request) {
                for (AntPathRequestMatcher rm : requestMatchers) {
                    if (rm.matches(request)) {
                        return false;
                    }
                }
                return true;
            }
        };

        // ログインしなくてもアクセスできるURL
        http.authorizeRequests()
                .antMatchers("/v1/login")
                .permitAll()
                .anyRequest().authenticated()   //上記にマッチしなければ未認証の場合エラー
                .and()
                .csrf()
                .requireCsrfProtectionMatcher(csrfRequestMatcher)
                .csrfTokenRepository(this.csrfTokenRepository());

        http.logout()
            .logoutUrl("/v1/logout")
            .permitAll();
    }


    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }
}

以下がフィルターの設定を行っている Java のソースです。

@Component
public class SimpleCORSFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.addHeader("Access-Control-Allow-Origin", "http://localhost:4200");
        response.addHeader("Access-Control-Allow-Credentials", "true");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With, X-XSRF-TOKEN");
        if ("OPTIONS".equals(request.getMethod())) {
            return;
        }
        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {}

}


以下がリクエスト送信部分です。

this.http.get(this.hostname + 'templates', { withCredentials: true, headers: this.headers }).subscribe(
      json => {
        this.templates = json;
      },
      error => {
        console.log(error);
      }
    );

 試したこと

  • csrf を disable にしました。
    エラー内容を見る限り、cors のフィルターと関係ない部分で拒否されていると考え、csrf を disable にしてみましたが、結果に変化はありませんでした。
  • Chrome のアプリケーション「ARC」を使って確認しました。
    ARCを使ってリクエストを送信したところ、通信に成功しました。ARC を使ったリクエストはプレフライトが行われていないので成功したのだと考えられます。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

自己解決できたので、解決方法を記入します。

SecurityConfig.java の最後に

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}


を加えることで、OPTIONS メソッドのリクエストを無条件許可することで通すことが出来ました。

Spring Securityの動きが分からない部分が多く、本当にこの対処法が良い対処法なのかもわからないので、もし他にもっと良い方法をご存知の方がいらっしゃれば引き続きご教授よろしくお願いします。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる