次の方法で共有


Azure Active Directory B2C を使用して Java Spring Boot アプリをセキュリティで保護する

この記事ではJava 用 Azure AD B2C Spring Boot Starter クライアント ライブラリを使用して Azure Active Directory B2C テナントのユーザーのサインインを行う Java Spring Boot Web アプリについて説明します。 OpenID Connect プロトコルを使用します。

次の図は、アプリのトポロジを示しています。

アプリのトポロジを示す図。

このクライアント アプリは Java 用の Azure AD B2C Spring Boot Starter クライアント ライブラリを使用してユーザーのサインインを行い、Azure AD B2C から ID トークンを取得します。 ID トークンにより、ユーザーが Azure AD B2C で認証され、保護されたルートにアクセスできることが証明されます。

前提条件

推奨事項

  • Spring Framework に関するある程度の知識。
  • Linux/OSX ターミナルに関するある程度の知識。
  • トークンの検査に必要な jwt.ms
  • ネットワークの活動監視とトラブルシューティングに必要な Fiddler
  • 開発に関する最新の情報について、Microsoft Entra ID ブログを確認してください。

サンプルのセットアップ

次のセクションでは、サンプル アプリケーションを設定する方法を示します。

サンプル リポジトリを複製またはダウンロードする

サンプルを複製するには、Bash ウィンドウを開き、次のコマンドを使用します。

git clone https://github.com/Azure-Samples/ms-identity-msal-java-samples.git
cd 4-spring-web-app/1-Authentication/sign-in-b2c

または、ms-identity-msal-java-samples リポジトリに移動し、.zip ファイルでダウンロードして、ハード ドライブに展開します。

重要

Windows でファイル パスの長さが制限を超える場合は、ハード ドライブのルート近くのディレクトリにリポジトリを複製または展開してください。

このサンプルには、デモのために事前に登録されたアプリケーションが含まれています。 自分の Azure AD B2C テナントとアプリケーションを使用する場合は、アプリケーションを Azure portal で登録して構成してください。 詳細については、「アプリの登録」セクションを参照してください。 そうでない場合は、「サンプルの実行」セクションの手順に進みます。

アプリケーションを作成するための Azure AD B2C テナントを選択する

テナントを選択するには、次の手順に従います。

  1. Azure portal にサインインします。

  2. ご利用のアカウントが複数の Azure AD B2C テナントに存在する場合は、Azure portal の画面の隅にあるプロファイルを選択し、ディレクトリの切り替えを選択して、ポータルのセッションを目的の Azure AD B2C テナントに変更します。

ユーザー フローとカスタム ポリシーの作成

サインアップ、サインイン、プロファイルの編集、パスワードのリセットなど、一般的なユーザー フローを作成するには、「チュートリアル: Azure Active Directory B2C 内にユーザー フローを作成する」を参照してください。

Azure Active Directory B2C でカスタム ポリシーを作成することも検討してください。 ただし、それについてはこのチュートリアルでは取り扱いません。 詳細については、「Azure AD B2C カスタム ポリシーの概要」を参照してください。

外部 ID プロバイダーを追加する

チュートリアル:Azure Active Directory B2C でアプリケーションに ID プロバイダーを追加する」を参照してください。

アプリを登録する (java-spring-webapp-auth-b2c)

アプリを登録するには、次の手順に従います。

  1. Azure portal に移動して、Azure AD B2C を選びます。

  2. ナビゲーション ペインでアプリの登録を選択し、新しい登録を選択します。

  3. 表示される アプリケーションの登録ページで、アプリケーションの登録情報を入力します。

    • 名前セクションに、アプリのユーザーに表示されるわかりやすいアプリケーション名を入力します (例: java-spring-webapp-auth-b2c)。
    • [サポートされているアカウントの種類] で、 [Accounts in any identity provider or organizational directory (for authenticating users with user flows)]((ユーザー フローを使用してユーザーを認証するための) 任意の ID プロバイダーまたは組織のディレクトリのアカウント) を選択します。
    • [リダイレクト URI (省略可能)] セクションで、コンボボックスの [Web] を選択し、リダイレクト URI 「http://localhost:8080/login/oauth2/code/」を入力します。
  4. [登録] を選択して、アプリケーションを作成します。

  5. アプリの登録ページで、アプリケーション (クライアント) ID の値を見つけてメモします。 この値は、後ほどアプリの構成ファイルで使用します。

  6. [保存] を選択して変更を保存します。

  7. アプリの登録ページで、ナビゲーション ペインにある 証明書とシークレット ペインを選択してページを開き、シークレットの生成と証明書のアップロードを行います。

  8. [クライアント シークレット] セクションで、 [新しいクライアント シークレット] を選択します。

  9. キーの説明 (例: アプリのシークレット) を入力します。

  10. 表示された期間から、セキュリティ要件に応じていずれかを選択します (例: 2 年)。

  11. [追加] を選択します。 生成された値が表示されます。

  12. 生成した値をコピーしてから保存します。 この値は後ほど、コードの構成ファイルに使用します。 この値は二度と表示されず、他の方法でも取得はできません。 そのため、必ず Azure portal から保存した後に、他の画面やペインに移動してください。

アプリ登録を使用するようにアプリ (java-spring-webapp-auth-b2c) を構成する

アプリを構成するには、次の手順に従います。

Note

以降の手順では、ClientIDApplication ID または AppId と同じです。

  1. IDE でプロジェクトを開きます。

  2. src/main/resources/application.yml ファイルを開きます。

  3. client-id プロパティを見つけて、既存の値をアプリケーション ID または Azure portal からコピーした java-spring-webapp-auth-b2c アプリケーションの clientId に変更します。

  4. client-secret プロパティを見つけて、Azure portal の java-spring-webapp-auth-b2c アプリケーションの作成時に保存した値に既存の値を置き換えます。

  5. base-uri プロパティを探して、値 fabrikamb2c の 2つのインスタンスを、Azure portal の java-spring-webapp-auth-b2c アプリケーションで作成した Azure AD B2C テナントの名前に置き換えます。

  6. sign-up-or-sign-in プロパティを見つけて、Azure portal で java-spring-webapp-auth-b2c アプリケーションを作成した際に、Azure AD B2C テナント で作成したサインアップ/サインイン ユーザー フロー ポリシーの名前に置き換えます。

  7. profile-edit プロパティを見つけて、Azure portal で java-spring-webapp-auth-b2c アプリケーションを作成した際に、Azure AD B2C テナント で作成したパスワード リセット ユーザー フロー ポリシーの名前に置き換えます。

  8. password-reset プロパティを見つけて、Azure portal で java-spring-webapp-auth-b2c アプリケーションを作成した際に、Azure AD B2C テナント で作成したプロファイル編集ユーザー フロー ポリシーの名前に置き換えます。

  9. src/main/resources/templates/navbar.html ファイルを開きます。

  10. b2c_1_susi フローと b2c_1_edit_profile フローへの参照を探して、それらを sign-up-sign-inprofile-edit のユーザーフローに置き換えます。

サンプルを実行する

以降のセクションでは、サンプルを Azure Container Apps にデプロイする方法を紹介します。

前提条件

  • Azure アカウント。 アカウントがない場合は、 無料アカウントを作成してください。 続行するには、Azure サブスクリプションの "共同作成者" または "所有者" のアクセス許可が必要です。 詳細については、Azure portal を使用して Azure ロールを割り当てる方法に関するページを参照してください。
  • Azure CLI
  • Azure Container Apps CLI 拡張機能バージョン 0.3.47 以上。 最新バージョンをインストールするには、az extension add --name containerapp --upgrade --allow-preview コマンドを使用します。
  • Java Development Kit バージョン 17 以上。
  • Maven

Spring プロジェクトを準備する

次の手順を実行して、プロジェクトを準備します。

  1. 次の Maven コマンドを使用して、プロジェクトをビルドします。

    mvn clean verify
    
  2. 次のコマンドを使用して、サンプル プロジェクトをローカルで実行します。

    mvn spring-boot:run
    

セットアップ

CLI から Azure にサインインするには、次のコマンドを実行し、プロンプトに従って認証プロセスを完了します。

az login

最新バージョンの CLI を実行していることを確認するには、upgrade コマンドを実行します。

az upgrade

次に、CLI 用の Azure Container Apps 拡張機能をインストールまたは更新します。

Azure CLI で az containerapp コマンドを実行するときにパラメーターが見つからないというエラーが表示された場合には、最新バージョンの Azure Container Apps 拡張機能がインストールされていることを確認してください。

az extension add --name containerapp --upgrade

Note

2024 年 5 月以降、Azure CLI 拡張機能では、既定でプレビュー機能が有効になりません。 Container Apps のプレビュー機能にアクセスするには、--allow-preview true を使用して Container Apps 拡張機能をインストールします。

az extension add --name containerapp --upgrade --allow-preview true

最新の拡張機能またはモジュールがインストールされたので、Microsoft.App および Microsoft.OperationalInsights 名前空間を登録します。

Note

Azure Container Apps リソースは、Microsoft.Web 名前空間から Microsoft.App 名前空間に移行されました。 詳細については、「2022 年 3 月に Microsoft.Web から Microsoft.App に名前空間を移行する」を参照してください。

az provider register --namespace Microsoft.App
az provider register --namespace Microsoft.OperationalInsights

Azure Container Apps 環境を作成する

Azure CLI のセットアップが完了したところで、この記事全体で使用される環境変数を定義できます。

bash シェルで次の変数を定義します。

export RESOURCE_GROUP="ms-identity-containerapps"
export LOCATION="canadacentral"
export ENVIRONMENT="env-ms-identity-containerapps"
export API_NAME="ms-identity-api"
export JAR_FILE_PATH_AND_NAME="./target/ms-identity-spring-boot-webapp-0.0.1-SNAPSHOT.jar"

リソース グループを作成する。

az group create  \
    --name $RESOURCE_GROUP \
    --location $LOCATION \

自動生成されたログ分析ワークスペースを使用して環境を作成します。

az containerapp env create \
    --name $ENVIRONMENT \
    --resource-group $RESOURCE_GROUP \
    --location $LOCATION

コンテナー アプリ環境の既定のドメインを表示します。 このドメインは、後のセクションで使用するためにメモしておきます。

az containerapp env show \
    --name $ENVIRONMENT \
    --resource-group $RESOURCE_GROUP \
    --query properties.defaultDomain

アプリのデプロイを準備する

アプリケーションを Azure Container Apps にデプロイすると、リダイレクト URL は、Azure Container Apps にデプロイされたアプリ インスタンスのリダイレクト URL に変更されます。 application.yml ファイルでこれらの設定を変更するには、次の手順に従います。

  1. アプリの src\main\resources\application.yml ファイルに移動し、post-logout-redirect-uri の値をデプロイされたアプリのドメイン名に変更します (次の例を参照)。 <API_NAME><default-domain-of-container-app-environment> は実際の値に置き換えてください。 たとえば、前の手順の Azure Container Apps 環境の既定のドメインを使用し、アプリ名に ms-identity-api を使用する場合、post-logout-redirect-uri 値には https://ms-identity-api.<default-domain> を使用します。

    post-logout-redirect-uri: https://<API_NAME>.<default-domain-of-container-app-environment>
    
  2. このファイルを保存した後、次のコマンドを使用してアプリをリビルドします。

    mvn clean package
    

重要

アプリケーションの application.yml ファイルには、クライアント シークレットの値が client-secret パラメーターに格納されています。 この値をこのファイルに保持しないでください。 また、ファイルを Git リポジトリにコミットすると、リスクが生じる可能性があります。 推奨される方法については、「Azure Container Apps でシークレットを管理する」を参照してください。

Microsoft Entra IDアプリの登録を更新する

リダイレクト URI は Azure Container Apps にデプロイされたアプリに変更されるため、Microsoft Entra ID アプリの登録でも、リダイレクト URI を変更する必要があります。 次の手順に従って、この変更を行います。

  1. 開発者用の Microsoft ID プラットフォームの [アプリの登録] ページに移動します。

  2. 検索ボックスを使用してアプリの登録を検索します (例: java-servlet-webapp-authentication)。

  3. 名前を選択して、アプリの登録を開きます。

  4. コマンドメニューから 認証 を選択します。

  5. Web - リダイレクト URI セクションで、URI の追加を選択します。

  6. アプリの URI を、/login/oauth2/code/ を追加して入力します。たとえば https://<containerapp-name>.<default domain of container app environment>/login/oauth2/code/ のようになります。

  7. [保存] を選択します。

アプリケーションのデプロイ

JAR パッケージを Azure Container Apps にデプロイします。

Note

必要に応じて、Java ビルド環境変数で JDK のバージョンを指定できます。 詳細については、Azure Container Apps の Java 用ビルド環境変数に関する記事を参照してください。

これで、az containerapp up CLI コマンドを使って WAR ファイルをデプロイできるようになります。

az containerapp up \
    --name $API_NAME \
    --resource-group $RESOURCE_GROUP \
    --location $LOCATION \
    --environment $ENVIRONMENT \
    --artifact <JAR_FILE_PATH_AND_NAME> \
    --ingress external \
    --target-port 8080 \
    --query properties.configuration.ingress.fqdn

Note

既定の JDK バージョンは 17 です。 アプリケーションとの互換性のために JDK のバージョンを変更する必要がある場合は、--build-env-vars BP_JVM_VERSION=<YOUR_JDK_VERSION> 引数を使ってバージョン番号を調整できます。

ビルド環境変数の詳細については、Azure Container Apps の Java 用ビルド環境変数に関する記事を参照してください。

アプリを検証する

この例では、containerapp up コマンドに --query properties.configuration.ingress.fqdn 引数が含まれており、完全修飾ドメイン名 (FQDN) (アプリの URL とも呼ばれます) を返します。 次の手順を使用して、アプリのログをチェックし、デプロイの問題があれば調査します。

  1. デプロイメント セクションの出力ページから出力アプリケーションの URL にアクセスします。

  2. Azure Container Apps インスタンスの[概要] ページのナビゲーション ウィンドウで、[ログ] を選択してアプリのログを確認します。

サンプルの確認

次の手順に従ってサンプルを操作します。

  1. サインインまたはサインアウトの状態が、画面の中央に表示されます。
  2. 画面の隅にある状況依存ボタンを選択します。 このボタンは、アプリを最初に実行するときにサインインと表示します。 または、トークンの詳細へのリンクを選択します。 このページは保護されており、認証が必要であるため、サインイン ページに自動でリダイレクトされます。
  3. 次のページに移動し、指示に従って、選択した ID プロバイダーのアカウントでサインインします。 また、メール アドレスを使用して、B2C テナントのローカル アカウントにサインアップまたはサインインすることもできます。
  4. サインイン フローが正常に完了するとホーム ページにリダイレクトされ、どのボタンでサインイン フローをトリガーした化に応じて、サインインの状態ページまたはトークンの詳細ページが表示されます。
  5. 状況依存ボタンの表示がサインアウトに変わり、ユーザー名が表示されます。
  6. ホーム ページを表示している場合は、IDトークンの詳細を選択して、IDトークンのデコードされた要求の一部を表示します。
  7. プロファイルを編集します。 プロファイルの編集を選択して、表示名、居住地、職業などの情報を変更します。
  8. 隅にあるボタンを使用してサインアウトします。新しい状態が状態ページに反映されます。

コードについて

このサンプルでは、Java 用 Azure AD B2C Spring Boot Starter クライアント ライブラリを使用して、Azure AD B2C テナントへのユーザーのサインインを行う方法を説明します。 このサンプルでは、Spring Oauth2 クライアントと Spring Web ブート スターターも使用します。 このサンプルでは、Azure AD B2C から取得した ID トークンにある要求を使用して、サインインしているユーザーの詳細を表示します。

Contents

次の表に、サンプル プロジェクト フォルダーの内容を示します。

ファイル/フォルダー 説明
pom.xml アプリケーションの依存関係。
src/main/resources/templates/ UI 用の Thymeleaf テンプレート。
src/main/resources/application.yml アプリケーションと Microsoft Entra Boot Starter ライブラリの構成。
src/main/java/com/microsoft/azuresamples/msal4j/msidentityspringbootwebapp/ このディレクトリには、メイン アプリケーションのエントリ ポイント、コントローラー、および構成のクラスが含まれています。
.../MsIdentitySpringBootWebappApplication.java Main クラス。
.../SampleController.java エンドポイントをマッピングするコントローラー。
.../SecurityConfig.java セキュリティ構成 - たとえば、認証が必要なルートを構成します。
.../Utilities.java ユーティリティ クラス - たとえば、ID トークン要求をフィルター処理します。
CHANGELOG.md サンプルに対する変更の一覧。
CONTRIBUTING.md サンプルに貢献するためのガイドライン。
ライセンス サンプルのライセンス。

ID トークン要求

アプリはトークンの詳細を抽出するために、Spring Security の AuthenticationPrincipalOidcUser オブジェクトを要求マッピングで使用します (次の例を参照)。 このアプリで ID トークン要求を使用する方法については、サンプル コントローラーを参照してください。

import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
//...
@GetMapping(path = "/some_path")
public String tokenDetails(@AuthenticationPrincipal OidcUser principal) {
    Map<String, Object> claims = principal.getIdToken().getClaims();
}

アプリはサインインを行うために、Java 用 Azure AD B2C Spring Boot Starter クライアント ライブラリで自動的に構成された Azure AD B2C サインイン エンドポイントに対して要求を行います (次の例を参照)。

<a class="btn btn-success" href="/oauth2/authorization/{your-sign-up-sign-in-user-flow}">Sign In</a>

アプリはサインアウトを行う際に、logout エンドポイントへの POST 要求を行います (次の例を参照)。

<form action="#" th:action="@{/logout}" method="post">
  <input class="btn btn-warning" type="submit" value="Sign Out" />
</form>

認証に依存する UI 要素

アプリの UI テンプレート ページに、ユーザーが認証済みかどうかに応じて表示するコンテンツを決定するためのシンプルなロジックがあります (Spring Security Thymeleaf タグを使用した次の例を参照)。

<div sec:authorize="isAuthenticated()">
  this content only shows to authenticated users
</div>
<div sec:authorize="isAnonymous()">
  this content only shows to not-authenticated users
</div>

WebSecurityConfigurerAdapter を使用してルートを保護する

既定では、ID トークンの詳細ページを保護するために、サインインしているユーザーのみにアクセスを許可します。 アプリは、application.yml ファイルにある app.protect.authenticated プロパティで、これらのルートを構成します。 アプリの特定の要件を構成するには、いずれのクラスで WebSecurityConfigurerAdapter を拡張します。 例については、このアプリの SecurityConfig クラスを参照してください (次の例を参照)。

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${app.protect.authenticated}")
    private String[] protectedRoutes;

    private final AADB2COidcLoginConfigurer configurer;

    public SecurityConfig(AADB2COidcLoginConfigurer configurer) {
        this.configurer = configurer;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.authorizeRequests()
            .antMatchers(protectedRoutes).authenticated()     // limit these pages to authenticated users (default: /token_details)
            .antMatchers("/**").permitAll()                  // allow all other routes.
            .and()
            .apply(configurer)
            ;
        // @formatter:off
    }
}

詳細

このシナリオおよびその他のシナリオでの OAuth 2.0 プロトコルの動作の詳細については、「Microsoft Entra ID の認証シナリオ」を参照してください。