以下の内容はhttps://miyohide.hatenablog.com/entry/2024/12/14/210250より取得しました。


Spring Boot + Amazon Cognitoのログアウト機能の実装で発生したInvalid Requestとその対処方法 サンプル実装の改善を添えて

先日よりAmazon Cognitoを使ってSpring Bootアプリに対して認証機能を実装しています。

miyohide.hatenablog.com

miyohide.hatenablog.com

今回はログアウト機能の実装中に少しハマったことがあったのでそのことについて記載します。

陥った現象

今回陥った現象は、正しく実装したログアウト処理を試そうとすると「Invalid Request」というメッセージが表示されるというものです。画面としては以下の画面が表示されます。

新しいAmazon CognitoではQuick Startとしてそれぞれの言語ごとに実装例が表示されるので、それを真似たらできるのですが今回私の場合では動かず。何度もコピペミスをしていないか確認しましたがどうも問題なさそうです。

もう少し深掘りしてみると、以下の状況になっていました。

  • ログアウト自身はうまくいっている感じ
    • 再度ログインしようとすると認証情報の入力が求められるため
  • 上記の画面のURLはAmazon Cognitoが指定しているURL + /logoutではなく、/loginになっている

このことから、ログアウト自身はうまくいっているがその後の移動処理でなんらかの不具合が発生しているように見えます。

原因

Amazon Cognitoの設定項目である「許可されているサインアウトURL」にパラメータlogout_uriとして指定しているURIに完全一致していないのが原因です。Amazon Cognitoの画面は以下のもの。

AWSの以下のドキュメントを見て気がつきました。

docs.aws.amazon.com

この中で、以下の記述があります。

logout_uri パラメータを使用して、ユーザーをカスタムサインアウトページにリダイレクトします。その値を、サインアウトURL後にユーザーをリダイレクトするアプリケーションクライアントサインアウトに設定します。

ずっとパラメータの名前や値を確認していて、Amazon Cognito自身の設定ができていなかったのは個人的には盲点でした。

注意点

パラメータlogout_uriAmazon Cognitoでの「許可されているサインアウトURL」は完全一致する必要があります。例えばhttp://localhost:8080http://localhost:8080/は違うものと扱われ「Invalid Request」というメッセージが表示されることになります。

実装の注意点と改善策

新しいAmazon CognitoではQuick Startとしてそれぞれの言語ごとに実装例が表示されるのですが、client_idの値がソースコード上に直接書かれておりあまり褒められたものではないです。個人的にはapplication.propertiesに書かれている値を読み取る形としたいです。具体的な実装としては以下の通り。

package com.github.miyohide.sb_with_cognito;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ResourceBundle;

public class CognitoLogoutHandler extends SimpleUrlLogoutSuccessHandler {

  @Override
  protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
    ResourceBundle resourceBundle = ResourceBundle.getBundle("application");
    String domain = resourceBundle.getString("app.cognito.domain");
    String logoutRedirectUrl = resourceBundle.getString("app.cognito.logout_uri");
    String userPoolClientId = resourceBundle.getString("spring.security.oauth2.client.registration.cognito.client-id");
    return UriComponentsBuilder
            .fromUri(URI.create(domain + "/logout"))
            .queryParam("client_id", userPoolClientId)
            .queryParam("logout_uri", logoutRedirectUrl)
            .encode(StandardCharsets.UTF_8)
            .build()
            .toUriString();
  }
}

最初はSpring Bootアプリなので@Valueを使おうとしたのですが、CognitoLogoutHandler@Componentなどを付与していないので、設定することができませんでした。そこで、ResourceBundlerを使った実装としました。




以上の内容はhttps://miyohide.hatenablog.com/entry/2024/12/14/210250より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14