適用対象: すべての API Management レベル
重要
2025 年 5 月 1 日より、Azure AD B2C は新規のお客様向けに購入できなくなります。 詳細については、FAQ を参照してください。
このシナリオでは、API を保護するように Azure API Management インスタンスを構成する方法について説明します。 Azure AD B2C SPA (Auth Code + PKCE) フローを使用してトークンを取得し、API Management と共に EasyAuth を使用して Azure Functions バックエンドをセキュリティで保護します。
API の認可の概念的概要については、API Management での API に対する認証と認可をご覧ください。
目的
ここでは、Azure Functions と Azure AD B2C を使用した簡略化されたシナリオで API Management を使用する方法を確認します。 Azure AD B2C を使用してユーザーをサインインさせる API を呼び出す JavaScript (JS) アプリを作成します。 次に、API Management の validate-jwt、CORS、および Rate Limit By Key ポリシー機能を使用して、バックエンド API を保護します。
多層防御のために、次に EasyAuth を使用してバックエンド API 内でトークンを再び検証し、API Management が Azure Functions バックエンドを呼び出すことができる唯一のサービスであることを確認します。
学習内容
- Azure Active Directory B2C でのシングル ページ アプリとバックエンド API のセットアップ
- Azure Functions バックエンド API の作成
- Azure API Management への Azure Functions API のインポート
- Azure API Management 内での API の保護
- Microsoft Identity Platform Library (MSAL.js) を使用した Azure Active Directory B2C 承認エンドポイントの呼び出し
- HTML/Vanilla JS シングル ページ アプリケーションを格納し、Azure Blob Storage エンドポイントから提供する
前提条件
この記事の手順を実行するには、以下が必要です。
- フロントエンドの JS シングル ページ アプリをホストする Azure (StorageV2) 汎用 V2 ストレージ アカウント。
- Azure API Management インスタンス ("従量課金" を含む任意のレベルで動作しますが、完全なシナリオに適用される特定の機能は、このレベルでは使用できません (キーごとのレート制限と専用仮想 IP)、これらの制限は、必要に応じて記事で以下に記載されています。
- 呼び出された API をホストする空の Azure Function アプリ (従量課金プランで V3.1 .NET Core ランタイムを実行)
- サブスクリプションにリンクされている Azure AD B2C テナント。
実際には、運用環境のワークロードで同じリージョンのリソースを使用しますが、このハウツー記事では、デプロイのリージョンは重要ではありません。
概要
使用中のコンポーネントと、このプロセスが完了した後のそれらの間のフローを次に示します。
手順の概要は次のとおりです。
スコープが指定された Azure AD B2C 呼び出し (フロントエンド、API Management) および API アプリケーションを作成し、API アクセスを許可します
サインアップおよびサインイン ポリシーを作成して、ユーザーが Azure AD B2C でサインインできるようにします
開発者コンソールで OAuth2 ユーザーの承認を有効にするように新しい Azure AD B2C クライアント ID とキーを使用して API Management を構成します
関数 API を構築します
新しい Azure AD B2C クライアント ID とキーで EasyAuth を有効にし、APIM VIP にロックダウンするように関数 API を構成します。
API Management で API 定義を構築します
API Management API 構成に OAuth2 を設定する
CORS ポリシーを設定し、validate-jwt ポリシーを追加して、すべての受信要求の OAuth トークンを検証します
API を使用する呼び出し元のアプリケーションを構築します
JS SPA サンプルをアップロードします
新しい Azure AD B2C クライアント ID とキーを使用してサンプル JS クライアント アプリを構成します。
クライアント アプリケーションをテストします
ヒント
我々はこのドキュメントを読み進める際に、かなりの情報やキーなどをキャプチャしますので、次の構成項目を一時的に格納するためにテキストエディターを開いておくと便利かもしれません。
B2C バックエンド クライアント ID: B2C バックエンド クライアントシークレット キー: B2C バックエンド API スコープ URI: B2C フロントエンド クライアント ID: B2C ユーザー フロー エンドポイント URI: B2C よく知られている OPENID エンドポイント: B2C ポリシー名: Frontendapp_signupandsignin 関数 URL: APIM API ベース URL: ストレージ プライマリ エンドポイント URL:
バックエンド アプリケーションを構成する
ポータルで [Azure AD B2C] ブレードを開き、次の手順を実行します。
[アプリの登録] タブを選択します
[新規登録] ボタンを選択します。
[リダイレクト URI] 選択ボックスで [Web] を選択します。
次に [表示名] を設定します。このとき、作成するサービスに関連する一意のものを選択します。 この例では、"Backend Application" という名前を使用します。
応答 URL には 'https://jwt.ms ' (Microsoft 所有のトークン デコード サイト) などのプレースホルダーを使用します。これらの URL は後で更新します。
[Accounts in any identity provider or organizational directory (for authenticating users with user flows)]((ユーザー フローを使用してユーザーを認証するための) 任意の ID プロバイダーまたは組織のディレクトリのアカウント) オプションを選択します
このサンプルでは、現在 offline_access アクセス許可を必要としないため、[管理者の同意の付与] チェックボックスをオフにします。
[登録] を選択します。
後で使用するために Backend Application のクライアント ID をメモします ([アプリケーション (クライアント) ID] の下に表示されます)。
[ 証明書とシークレット ] タブ ([管理] の下) を選択し、[新しいクライアント シークレット] を選択して認証キーを生成します (既定の設定をそのまま使用し、[追加] を選択します)。
[追加] をクリックすると、後で "バックエンド クライアント シークレット" として安全な場所にキー ([値] の下) をコピーします。このダイアログは、このキーをコピーする必要がある唯一の可能性があることに注意してください。
次に、 [API の公開] タブ ([管理] の下) を選択します。
AppID URI を設定し、既定値を選択して記録するように求められます。
関数 API のスコープ "Hello" を作成して名前を付けます。入力可能なすべてのオプションに対して "Hello" という語句を使用し、設定されたフル スコープ値 URI を記録してから、[スコープの追加] を選択できます。
ポータルの左上にある [Azure AD B2C] 階層リンクを選択して、Azure AD B2C ブレードのルートに戻ります。
注
Azure AD B2C スコープは、他のアプリケーションを使ってアプリケーションから API アクセス ブレードを介してアクセスを要求できる、API 内の事実上のアクセス許可です。実際、ここでは呼び出された API のアプリケーション アクセス許可を作成しました。
フロントエンド アプリケーションを構成する
- [アプリの登録] タブを選択します
- [新規登録] ボタンを選択します。
- [リダイレクト URI] 選択ボックスで [シングル ページ アプリケーション (SPA)] を選択します。
- ここで [表示名] と [AppID URI] を設定します。このとき、この Azure Active Directory B2C アプリ登録を使用するフロントエンド アプリケーションに関連する一意のものを選択します。 この例では、"Frontend Application" を使用できます
- 最初のアプリの登録に従って、[サポートされているアカウントの種類] の選択を既定のままにします (ユーザー フローでユーザーを認証する)
- 応答 URL には 'https://jwt.ms ' (Microsoft 所有のトークン デコード サイト) などのプレースホルダーを使用します。これらの URL は後で更新します。
- [管理者の同意の付与] チェックボックスをオンのままにします
- [登録]を選択します。
- 後で使用するために Frontend Application のクライアント ID をメモします ([アプリケーション (クライアント) ID] の下に表示されます)。
- [API のアクセス許可] タブに切り替えます。
- [アクセス許可の追加]、[マイ API] の順にクリックしてバックエンド アプリケーションへのアクセスを許可し、[バックエンド アプリケーション] を選択し、[アクセス許可] を選択し、前のセクションで作成したスコープを選択して、[アクセス許可の追加] を選択します。
- [{tenant} に管理者の同意を与える] を選択し、ポップアップ ダイアログから [はい] を選択します。 このポップアップでは、前に作成した "Backend Application" で定義されているアクセス許可 "hello" を "Frontend Application" で使用することに同意します。
- アプリの [すべてのアクセス許可] には、[状態] 列の下に緑色のチェックが表示されます
"サインアップとサインイン" ユーザー フローを作成する
[Azure AD B2C] 階層リンクを選択して、B2C ブレードのルートに戻ります。
[ユーザー フロー] タブ ([ポリシー] の下) に切り替えます。
[新しいユーザー フロー] を選択する
ユーザー フローの種類として [サインアップとサインイン] を選択し、[推奨] を選択してから [作成] を選択します
ポリシーに名前を付け、後で使用できるようにメモします この例では、"Frontendapp_signupandsignin" を使用できます。このプレフィックスには "B2C_1_" が付き、"B2C_1_Frontendapp_signupandsignin" を作成します。
[ID プロバイダー] と [ローカル アカウント] で、[電子メール のサインアップ] (B2C テナントの構成に応じて [ユーザー ID サインアップ] ) をオンにし、[OK] を選択します。 この構成を行う理由は、ユーザーの既存のソーシャル メディア アカウントを使用するために、別の ID プロバイダー (ソーシャル ID プロバイダーなど) に従うのではなく、ローカルの B2C アカウントを登録するためです。
MFA と条件付きアクセスの設定は、既定値のままにしておきます。
[ユーザー属性と要求] で 、[詳細を表示...] を選択します。次に、ユーザーに入力してトークンで返す要求オプションを選択します。 少なくとも、収集するものとして [表示名] と [メール アドレス]、返すものとして [表示名] と [メール アドレス] をオンにして (収集するのは 1 つのメール アドレス、返すのは複数のメール アドレスであることに注意してください)、[OK] を選んでから、[作成] を選びます。
一覧で作成したユーザー フローを選択し、[ユーザー フローの実行] ボタンを選択します。
このアクションにより、ユーザー フローの実行ブレードが開き、フロントエンド アプリケーションを選択し、ユーザー フロー エンドポイントをコピーして後で使用できるように保存します。
上部のリンクをコピーして保存し、後で使用できるように '既知の openid 構成エンドポイント' としてメモします。
注
B2C ポリシーを使用すると、Azure AD B2C ログイン エンドポイントを公開して、さまざまなデータ コンポーネントをキャプチャし、ユーザーのサインインにさまざまな方法を使用できるようになります。
この例では、サインアップまたはサインイン フロー (ポリシー) を構成しました。 これにより、既知の構成エンドポイントも公開されました。どちらの場合も、作成したポリシーは、"p =" クエリ文字列パラメーターによって URL で識別されていました。
これが完了すると、ユーザーを複数のアプリケーションにサインインさせる機能的な B2C ID プラットフォームを利用できるようになります。
関数 API を構築する
Azure portal で標準の Microsoft Entra テナントに切り替えて、サブスクリプションの項目を再構成できるようにします。
Azure portal の [Function Apps] ブレードに移動し、空の関数アプリを開き、[Functions] を選択し、[追加] を選択します。
表示されるポップアップで、[ポータルで開発] を選択し、[テンプレートの選択] で [HTTP トリガー] を選択し、[テンプレートの詳細] で承認レベル "関数" で "hello" という名前を付け、[追加] を選択します。
[コードとテスト] ブレードに切り替え、下にあるサンプル コードをコピーし、表示されている "既存のコードに重ねて" 貼り付けます。
[保存] を選択します。
using System.Net; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; public static async Task<IActionResult> Run(HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); return (ActionResult)new OkObjectResult($"Hello World, time and date are {DateTime.Now.ToString()}"); }
ヒント
先ほど貼り付けた C# スクリプト関数コードを実行すると、単に 1 行が関数ログに記録され、いくつかの動的データ (日付と時刻) と共に "Hello World" というテキストが返されます。
左側のブレードから [統合] を選択し、[トリガー] ボックス内の http (req) リンクを選択します。
[Selected HTTP methods]\(選択された HTTP メソッド\) ドロップダウンから http POST メソッドをオフにし、GET のみを選択したまま、[保存] を選択します。
[コード + テスト] タブに戻り、[Get Function URL]\(関数 URL の取得\) を選択し、表示される URL をコピーして後で保存します。
注
先ほど作成したバインドによって、単に先ほどコピーした URL (
https://yourfunctionappname.azurewebsites.net/api/hello?code=secretkey
) に匿名の HTTP GET 要求で応答するように Functions に指示されます。 これで、単純なペイロードを返せるスケーラブルなサーバーレス https API が作成されました。先ほどコピーして保存したものと同じバージョンの URL を使用して、この API を Web ブラウザーから呼び出すことをテストできるようになりました。 また、URL のクエリ文字列パラメーター "?code=secretkey" 部分を削除し、もう一度テストして、Azure Functions から 401 エラーが返されることを証明することもできます。
関数 API の構成とセキュリティ保護
関数アプリの領域をさらに 2 つ構成する必要があります (承認とネットワークの制限)。
まず、[認証/承認] を構成します。階層リンクを使用して関数アプリのルート ブレードに戻ります。
次に、([設定] の下の) [認証] を選択します。
[Add Identity Provider]\(ID プロバイダーの追加\) を選択します
[ID プロバイダー] ドロップダウンで [Microsoft] を選択します。
[アプリの登録] で、[既存のアプリの登録に関する詳細を指定してください] を選択します。
バックエンド アプリケーションのクライアント ID を (Azure AD B2C から) [アプリケーション (クライアント) ID] ボックスに貼り付けます (この構成は以前にメモしました)。
既知の open-id 構成エンドポイントを、サインアップおよびサインイン ポリシーから [発行者 URL] ボックスに貼り付けます (この構成は以前の手順でメモしました)。
バックエンド アプリケーションのクライアント シークレットを該当するボックスに貼り付けます (この構成は以前にメモしました)。
[認証されていない要求] で、[HTTP 401 非認可: API に推奨] を選択します。
[トークン ストア] は有効のままにしておきます (デフォルト)。
ブレードの左上にある [保存] を選択します。
重要
これで、関数 API がデプロイされたので、正しい JWT が Authorization: Bearer ヘッダーとして指定されないと 401 応答がスローされ、有効な要求が提示されるとデータが返されます。 認証されていない要求を処理するための [Microsoft Entra ID でのログイン] オプションを構成することで、EasyAuth に多層防御セキュリティを追加しました。
IP セキュリティはまだ適用されていません。有効なキーと OAuth2 トークンがあれば、誰でもこれをどこからでも呼び出すことができます。すべての要求が API Management を経由するよう強制するのが理想的です。
API Management の従量課金、Basic v2、Standard v2、Premium v2 レベルをお使いの場合は、関数のアクセス制限を許可リストに載せるための専用の Azure API Management 仮想 IP はありません。 Azure API Management クラシック (専用) レベルでは、VIP はシングル テナントであり、リソースの有効期間が対象です。 共有インフラストラクチャ上で実行されているレベルでは、上記でコピーした URI の部分にある共有シークレット関数キーを使用して、API 呼び出しをロックダウンできます。 また、これらのレベルでは、以下の手順 12 から 17 は適用されません。
App Service/Functions ポータルから [認証] ブレードを閉じます。
"ポータルの API Management ブレード" を開き、次に "インスタンス" を開きます。
[概要] タブに表示されるプライベート VIP をメモします。
"ポータルの Azure Functions ブレード" に戻り、"インスタンス" を再度開きます。
[ネットワーク] を選択し、[アクセス制限を構成する] を選択します
[規則の追加] を選択し、上記の手順 3 でコピーした VIP を xx.xx.xx.xx/32 の形式で入力します。
関数ポータルとの対話を続行し、以下の省略可能な手順を実行する場合は、独自のパブリック IP アドレスまたは CIDR 範囲を追加する必要があります。
一覧に許可エントリがあると、Azure によって暗黙的な拒否ルールが追加され、他のすべてのアドレスがブロックされます。
IP 制限パネルに、CIDR 形式のアドレス ブロックを追加する必要があります。 API Management VIP などの単一のアドレスを追加する必要がある場合は、xx.xx.xx.xx/32 の形式で追加する必要があります。
注
これで、関数 API は、API 管理やアドレス以外の場所から呼び出すことはできません。
"API Management ブレード" を開き、次に "インスタンス" を開きます。
API ブレード ([API] の下) を選択します。
[Add a New API](新しい API の追加) ペインから [関数アプリ] を選択し、ポップアップの上部から [完全] を選択します。
[参照] をクリックして、内部で API をホストしている関数アプリを選択し、[選択] をクリックします。 次に [選択] を再びクリックします。
API に API Management 内部で使用するための名前と説明を付けて、"無制限" の製品に追加します。
API の 'ベース URL' をコピーして記録し、[作成] を選択します。
[設定] タブを選択し、[サブスクリプション] で [サブスクリプションが必要] チェックボックスをオフにします。この場合、OAuth JWT を使用してレート制限を行います。 従量課金レベルを使用している場合、これは運用環境でも必要になることに注意してください。
ヒント
APIM の従量課金レベルを使用している場合は、無制限の製品をすぐに使用することはできません。 代わりに、[API] の下の [製品] に移動し、[追加] をクリックします。製品名と説明として「無制限」と入力し、追加した API を画面左下の [+] API 吹き出しから選択します。 [公開済み] チェックボックスを選択します。 残りは既定値のままにします。 最後に、[作成] ボタンをクリックします。 これにより、"unlimited" の製品が作成され、API に割り当てられました。 後で新しい製品をカスタマイズできます。
正しいストレージ エンドポイント設定を構成してキャプチャする
Azure portal で [ストレージ アカウント] ブレードを開きます
作成したアカウントを選択し、[設定] セクションから [静的な Web サイト] ブレードを選択します ([静的な Web サイト] オプションが表示されない場合は、V2 アカウントを作成したことを確認します)。
静的 Web ホスティング機能を "有効" に設定し、インデックス ドキュメント名を "index.html' に設定し、[保存] を選択します。
[プライマリ エンドポイント] の内容をメモしておきます。この場所はフロントエンド サイトがホストされる場所であるためです。
ヒント
Azure Blob Storage + CDN 書き換え、または SPA をホストするための Azure App Service のいずれかを使用できますが、BLOB Storage の静的 Web サイト ホスティング機能には、Azure Storage から静的 Web コンテンツ、html、js、および css を提供する既定のコンテナーが用意されているので、作業なしの既定のページが想定されます。
[CORS] および [validate-jwt] ポリシーを設定する
使用されている APIM レベルに関係なく、以下のセクションに従うようにします。 ストレージ アカウント URL は、この記事の上部にある前提条件から使用できるようにするストレージ アカウントのものです。
ポータルの API Management ブレードに切り替え、インスタンスを開きます。
[API] を選択し、[すべての API] を選択します。
[受信処理] で、コード ビュー ボタン "</>" を選択してポリシー エディターを表示します。
[受信] セクションを編集し、次のように XML を貼り付けます。
ポリシー内で次のパラメーターを置き換えます
{PrimaryStorageEndpoint} (前のセクションでコピーした 'Primary Storage Endpoint')、{b2cpolicy-well-known-openid} (以前コピーした '既知の openid 構成エンドポイント') および正しい値が上記で保存された {backend-api-application-client-id} (バックエンド API に対する B2C アプリケーション/クライアント ID)。
API Management の従量課金レベルを使用している場合は、両方の rate-limit-by-key ポリシーを削除する必要があります。これは、Azure API Management の従量課金レベルを使用するときにこのポリシーを利用できないためです。
<inbound> <cors allow-credentials="true"> <allowed-origins> <origin>{PrimaryStorageEndpoint}</origin> </allowed-origins> <allowed-methods preflight-result-max-age="120"> <method>GET</method> </allowed-methods> <allowed-headers> <header>*</header> </allowed-headers> <expose-headers> <header>*</header> </expose-headers> </cors> <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid." require-expiration-time="true" require-signed-tokens="true" clock-skew="300"> <openid-config url="{b2cpolicy-well-known-openid}" /> <required-claims> <claim name="aud"> <value>{backend-api-application-client-id}</value> </claim> </required-claims> </validate-jwt> <rate-limit-by-key calls="300" renewal-period="120" counter-key="@(context.Request.IpAddress)" /> <rate-limit-by-key calls="15" renewal-period="60" counter-key="@(context.Request.Headers.GetValueOrDefault("Authorization","").AsJwt()?.Subject)" /> </inbound>
注
これで、Azure API Management は JavaScript SPA アプリからのクロス オリジン要求に応答できるようになり、要求を Function API に転送する前に渡される JWT 認証トークンの調整、レート制限、および事前検証が実行されます。
これで、Azure AD B2C、API Management、Azure Functions が連携して API を発行、セキュリティで保護、使用できるようになりました。
ヒント
API Management の従量課金レベルを使用している場合、JWT サブジェクトまたは受信 IP アドレスによるレート制限ではなく (キー ポリシーによる呼び出しレートの制限は "従量課金" レベルでは現在サポートされていません)、呼び出しレートのクォータによって制限できます。こちらを参照してください。 この例は JavaScript シングル ページ アプリケーションなので、ここではレート制限と請求の呼び出しにのみ API Management キーを使用します。 実際の承認と認証は、Azure AD B2C によって処理され、JWT にカプセル化されます。これは 2 回検証されます (API Management による 1 回の後にバックエンドの Azure Functions)。
JavaScript SPA サンプルを静的ストレージにアップロードする
引き続きストレージ アカウント ブレードで、Blob Service セクションから [コンテナー] ブレードを選択し、右側のウィンドウに表示される$web コンテナーを選択します。
次のコードをマシン上のローカルのファイルに index.html という名前で保存し、ファイル index.html を $web コンテナーにアップロードします。
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous"> <script type="text/javascript" src="https://alcdn.msauth.net/browser/2.11.1/js/msal-browser.min.js"></script> </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-md-12"> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container-fluid"> <a class="navbar-brand" href="#">Azure Active Directory B2C with Azure API Management</a> <div class="navbar-nav"> <button class="btn btn-success" id="signinbtn" onClick="login()">Sign In</a> </div> </div> </nav> </div> </div> <div class="row"> <div class="col-md-12"> <div class="card" > <div id="cardheader" class="card-header"> <div class="card-text"id="message">Please sign in to continue</div> </div> <div class="card-body"> <button class="btn btn-warning" id="callapibtn" onClick="getAPIData()">Call API</a> <div id="progress" class="spinner-border" role="status"> <span class="visually-hidden">Loading...</span> </div> </div> </div> </div> </div> </div> <script lang="javascript"> // Just change the values in this config object ONLY. var config = { msal: { auth: { clientId: "{CLIENTID}", // This is the client ID of your FRONTEND application that you registered with the SPA type in Azure Active Directory B2C authority: "{YOURAUTHORITYB2C}", // Formatted as https://{b2ctenantname}.b2clogin.com/tfp/{b2ctenantguid or full tenant name including onmicrosoft.com}/{signuporinpolicyname} redirectUri: "{StoragePrimaryEndpoint}", // The storage hosting address of the SPA, a web-enabled v2 storage account - recorded earlier as the Primary Endpoint. knownAuthorities: ["{B2CTENANTDOMAIN}"] // {b2ctenantname}.b2clogin.com }, cache: { cacheLocation: "sessionStorage", storeAuthStateInCookie: false } }, api: { scopes: ["{BACKENDAPISCOPE}"], // The scope that we request for the API from B2C, this should be the backend API scope, with the full URI. backend: "{APIBASEURL}/hello" // The location that we'll call for the backend api, this should be hosted in API Management, suffixed with the name of the API operation (in the sample this is '/hello'). } } document.getElementById("callapibtn").hidden = true; document.getElementById("progress").hidden = true; const myMSALObj = new msal.PublicClientApplication(config.msal); myMSALObj.handleRedirectPromise().then((tokenResponse) => { if(tokenResponse !== null){ console.log(tokenResponse.account); document.getElementById("message").innerHTML = "Welcome, " + tokenResponse.account.name; document.getElementById("signinbtn").hidden = true; document.getElementById("callapibtn").hidden = false; }}).catch((error) => {console.log("Error Signing in:" + error); }); function login() { try { myMSALObj.loginRedirect({scopes: config.api.scopes}); } catch (err) {console.log(err);} } function getAPIData() { document.getElementById("progress").hidden = false; document.getElementById("message").innerHTML = "Calling backend ... " document.getElementById("cardheader").classList.remove('bg-success','bg-warning','bg-danger'); myMSALObj.acquireTokenSilent({scopes: config.api.scopes, account: getAccount()}).then(tokenResponse => { const headers = new Headers(); headers.append("Authorization", `Bearer ${tokenResponse.accessToken}`); fetch(config.api.backend, {method: "GET", headers: headers}) .then(async (response) => { if (!response.ok) { document.getElementById("message").innerHTML = "Error: " + response.status + " " + JSON.parse(await response.text()).message; document.getElementById("cardheader").classList.add('bg-warning'); } else { document.getElementById("cardheader").classList.add('bg-success'); document.getElementById("message").innerHTML = await response.text(); } }).catch(async (error) => { document.getElementById("cardheader").classList.add('bg-danger'); document.getElementById("message").innerHTML = "Error: " + error; }); }).catch(error => {console.log("Error Acquiring Token Silently: " + error); return myMSALObj.acquireTokenRedirect({scopes: config.api.scopes, forceRefresh: false}) }); document.getElementById("progress").hidden = true; } function getAccount() { var accounts = myMSALObj.getAllAccounts(); if (!accounts || accounts.length === 0) { return null; } else { return accounts[0]; } } </script> </body> </html>
以前に前のセクションで保存した静的な Web サイトのプライマリ エンドポイントを参照してください。
注
これで、JavaScript シングル ページ アプリが Azure Storage Static コンテンツ ホスティングにデプロイされました。 Azure AD B2C の詳細を使用して JS アプリをまだ構成していないため、このページを開いても、まだ機能しません。
Azure AD B2C 用に JavaScript SPA を構成する
- すべての場所がわかるようになったら、適切な API Management API アドレスと正しい Azure AD B2C アプリケーションおよびクライアント ID を使用して SPA を構成できます。
- Azure portal ストレージ ブレードに戻ります
- [Containers](コンテナー) を選択します ([設定] の下)
- 一覧から '$web' コンテナーを選択します
- 一覧から index.html BLOB を選択します
- [編集] を選択する
- 前に B2C で登録したフロントエンドアプリケーションと一致するように、MSAL config セクションの auth 値を更新します。 config 値がどのように表示されるかに関するヒントについては、コードのコメントを使用します。 authority の値は、次の形式にする必要があります: https://{b2ctenantname}.b2clogin.com/tfp/{b2ctenantname}.onmicrosoft.com}/{signupandsigninpolicyname}。サンプル名を使用し、b2c テナントを "contoso" とする場合、authority は 'https://contoso.b2clogin.com/tfp/contoso.onmicrosoft.com/Frontendapp_signupandsignin ' となることが想定されます。
- バックエンド アドレスと一致するように API 値を設定します (前に記録した API ベースの URL と、 バックエンド アプリケーションの 'b2cScopes' の値が前に記録されました)。
- [保存] を選択します。
Azure AD B2C フロントエンド アプリのリダイレクト URI を設定する
[Azure AD B2C] ブレードを開き、JavaScript フロントエンド アプリケーションのアプリケーション登録に移動します。
[リダイレクト URI] を選択し、前に入力したプレースホルダー 'https://jwt.ms' を削除します。
プライマリ (ストレージ) エンドポイントの新しい URI を追加します (末尾のスラッシュを除く)。
注
この構成の結果、フロントエンド アプリケーションのクライアントは、Azure AD B2C から適切な要求を含むアクセス トークンを受け取ります。 SPA を使って、バックエンド API への呼び出しの https ヘッダーにベアラー トークンとしてこれを追加できます。
API Management は、トークンを事前検証し、Azure ID (ユーザー) と呼び出し元の IP アドレスによって発行された JWT の両方のサブジェクトによってエンドポイントの呼び出しをレート制限してから (API Management のサービス レベルによって異なります。上記の注記を参照)、要求を受信側の Azure Function API に渡し、関数セキュリティ キーを追加します。 SPA によって、ブラウザーに応答が表示されます。
Azure AD B2C、Azure API Management、Azure Functions、Azure App Service Authorization が完全に調和するように構成されました。
これで、セキュリティで保護されたシンプルな API を使用するシンプルなアプリができました。テストしてみましょう。
クライアント アプリケーションをテストする
- 以前の手順で作成したストレージ アカウントからメモしたサンプル アプリの URL を開きます。
- 右上隅にある [サインイン] を選択すると、このアクションによって Azure AD B2C のサインアップまたはサインイン プロファイルがポップアップ表示されます。
- アプリは B2C プロファイル名を使用して開始されます。
- [API の呼び出し] を選択すると、セキュリティで保護された API から返された値でページが更新されます。
- [API の呼び出し] ボタンを 繰り返し 選択し、API Management の開発者層以上で実行している場合は、ソリューションで API のレート制限が開始され、この機能が適切なメッセージでアプリで報告されることに注意してください。
完了です
Azure AD B2C と API Management のさまざまな用途に合わせて、上記の手順を調整および編集できます。
関連コンテンツ
- Microsoft Entra ID と OAuth2.0 についてさらに学習します。
- API Management の詳細 を 確認してください。
- バックエンド サービスを保護するその他の方法については、「相互証明書認証」を参照してください。
- API Management サービス インスタンスの作成。
- Azure API Management での最初の API の管理。