1. 記事一覧 >
  2. ブログ記事
Azure
category logo

MSAL Reactを使用してサインインするSPAをAzure Static Web Appsにデプロイ

(更新) (公開)

はじめに

MSAL を使って Azure Active Directory (Azure AD) のユーザーでサインイン(ログイン)できるシングルページアプリケーションを Azure Static Apps にデプロイしました。
とは言っても、自力でアプリを実装した話ではなく、公式サンプルのソースコードをデプロイしただけです。デプロイ手順は、公式サンプルにあるチュートリアルを実施しました。
それだけの場合、チュートリアルを読めば分かる話ですが、気を付けないといけないこと等ありましたので、この記事に書くことにしました。
さらに、本家には無い画面の画像を使って説明してきます。本家に載っていないことも書いています。


この記事にソースコードの説明は有りません。

2022/07 現在の内容をベースにしています。

今回、サインインするユーザーは、会社や組織のアカウントを想定し、Azure AD を使用します。"Azure AD" は、一般ユーザー(Googleアカウントなど)を扱う Azure AD (B2B) の事ではありません。


作業にあたり、前提としては、以下になります。
・Azure AD テナント作成済み
・操作している人は、Azure AD テナント管理ができたり、Azure Static Web Apps にアプリをデプロイできるものとします。
・今回操作対象のテナントには、サインインできるユーザーアカウントがあるものとします。(操作している人でも良いですが。)
・VS Code(Visual Studio Code) インストール済み
・VS Code に Azure Static Web Apps 拡張機能 インストール済み
・GitHub アカウント登録済み(リポジトリ作成可)
Azure-Samples/ms-identity-javascript-react-tutorial4-Deployment/2-deploy-static のソースコード群が D:\sample に配置済みとします。(配置場所はどこでも良いです。)

ソースコード群配置済み


用語まとめ

【 MSAL 】

Microsoft Authentication Library(MSAL)は、マイクロソフト社提供の認証セキュリティ系機能を提供するライブラリです。

MSAL は、.NET、JavaScript、Java、Python、Android、iOS などの、さまざまなアプリケーション アーキテクチャとプラットフォームをサポートします。

MSAL は Azure AD および Azure AD B2C の両方に対応しています。

【 React 】

React (リアクト) は、Meta(旧Facebook)とコミュニティによって開発されているユーザインタフェース構築のためのJavaScriptライブラリです。

Reactはシングルページアプリケーションやモバイルアプリケーションの開発におけるベースとして使用することができます。

【 SPA 】

シングルページアプリケーション(single-page application、SPA)とは、単一のWebページのみから構成することで、デスクトップアプリケーションのようなユーザ体験を提供するWebアプリケーションまたはWebサイトです。

【 Azure AD 】

Azure Active Directory (Azure AD) は、クラウドベースの ID およびアクセス管理サービスです。

テナント/ディレクトリ、サブスクリプション、リソースなどの用語が有ります。それぞれを詳しく知るには、他の記事をあたった方が良いですが、ざっくりとした関係性は以下のMicrosoft公式ドキュメントの図のようになります。

画像リンク元:Azure 課金プランと Active Directory Domain Services テナント - 設計領域の概要

az-scopes-billing

画像リンク元:従来のサブスクリプション管理者ロール、Azure ロール、および Azure AD ロール - 各ロールの関係

rbac-admin-roles

画像リンク元:Azure 管理グループとは - 管理グループとサブスクリプションの階層

tree

【 Azure Static Web Apps 】

Azure Static Web Apps は、コードリポジトリ(GitHub)から Azure に静的 Web アプリを自動的にビルドしてデプロイするサービスです。

APIは、api/*(例:api/HelloUser/index.js) に実装すると、Azure Functions にデプロイされて、動的になります。


シナリオ

1.クライアントアプリケーションは、MSAL Reactを使用してユーザーにサインインし、Azure ADからJWT アクセストークンを取得します。
2.アクセストークンは、POSTリクエストを使用して Function API(/api/HelloUser)に送信されます。
3.Function API は、アクセストークンを検証し、Azure AD から新しいアクセストークンを取得します。
4.Function API は、新しいアクセストークンを Microsoft Graph API への Bearer トークン として使用します。(Authorization: Bearerヘッダに載せる)
5.Microsoft Graph APIが応答し、Function API がそれをクライアントアプリケーションに伝播します。

【 JWT 】

JSON Web Token(ジェイソン・ウェブ・トークン)は、JSONデータに署名や暗号化を施す方法を定めたオープン標準 (RFC 7519) です。

【 Microsoft Graph API 】

Azure Active Directory で管理されている様々なデータにアクセス可能なAPIです。主なAPIの機能として、Azure Active Directory で管理されているOffice365のデータへのアクセスが可能です。

【 Bearerトークン 】

Bearer(ベアラー)=(小切手・手形の)持参人。

BearerトークンはBearer(それを持ってきた存在)にアクセス権限を与える特性を持ちます。


On-behalf-of (OBO)フロー
本家チュートリアルでは、詳しく触れられていませんが、Profile、FunctionAPI とでは、フローが異なります。

Profile、FunctionAPI とでは、フローが異なります。


Profile
Microsoft Graph API を直接呼び出しています。 Microsoft Graph APIを直接呼び出し


FunctionAPI
Azure によって保護された自前の API から Microsoft Graph API を呼び出しています。(Microsoft Graph API はサインインした人から呼び出されていません。)上記シナリオは、こちらのことです。 APIからMicrosoft Graph API

【 On-behalf-of (OBO) 】

OAuth 2.0 の On-Behalf-Of (OBO) フローは、アプリケーションがサービス/Web API を呼び出し、それがさらに別のサービス/Web API を呼び出す必要のあるユース ケースに対応します。


アプリの登録

Azure AD のテナントに SPA アプリ(Reactと/api/hello)の情報について登録します。
アプリのソースコードを登録したりとか、インストールしたりとかの意味ではありません。


1.
Azure ポータル(https://portal.azure.com/)にアクセスして、Azure Active Directory をクリックします。

Azure Active Directory をクリック


2.
アプリの登録新規登録 をクリックします。

アプリの登録→新規登録 をクリック


3.
アプリ情報を入力します。
名前msal-react-spa
サポートされているアカウントの種類この組織ディレクトリのみに含まれるアカウント (<テナント名> のみ - シングル テナント)
リダイレクト URI (省略可能)シングルページアプリケーション (SPA) http://localhost:3000/

リダイレクト URIは、アプリのURLで、今回、Azure Static Appsにデプロイし、http://localhost:3000/ ではないため、後で変える手順があります。

アプリ情報を入力


4.
登録 をクリックします。


5.
アプリケーション (クライアント) IDディレクトリ (テナント) ID が表示されます。これは、後で設定するところで必要になります。この アプリの概要 画面で何度でも確認できます。

アプリの概要


6.
原文は、

6.Select Save to save your changes.
ですが、それにあたる操作はありませんでした。 (アプリの登録は完了しています。)

アプリの登録 からアプリを作成したら、“エンタープライズ アプリケーション“ も同時に作成されます。

このエンタープライズ アプリケーションは、“サービス プリンシパル“ と呼ばれるオブジェクトです。

正確にはエンタープライズ アプリケーションがサービス プリンシパルの一種ですが基本的には “サービス プリンシパル” と “エンタープライズ アプリケーション”はほぼ同義だと考えて OK です。

(参考:https://jpazureid.github.io/blog/azure-active-directory/oauth2-application-resource-and-api-permissions/

“サービス プリンシパル” と “エンタープライズ アプリケーション”はほぼ同義だと考えて OK

7.
アプリの概要 画面のまま、左側にある 証明書とシークレット をクリックします。証明書とシークレット 画面は、シークレットを作成したり、証明書をアップロードできる画面です。

証明書とシークレット


8.
クライアントシークレット を選択して、新しいクライアントシークレット をクリックします。

説明:app secret
有効期限:12 ヵ月(任意)
とし、追加 をクリックします。

新しいクライアントシークレット

追加し終わると、シークレット ID が表示されます。これは、他の画面に移ると、二度と表示されませんので、どこかへコピーペーストしておく必要があります。

後で必要になるのは、値 の方です。

値とシークレット ID


9.

左側から API の公開 をクリックし、Scope の追加 をクリックします。

API の公開 Scope の追加

ここで言うAPIとは、自分のAPI /api/hello のことです。


アプリケーション ID の URIapi://{clientId} で表示されるため、そのままにして、保存してから続ける をクリックします。

アプリケーション ID の URI


10.
API の URI に加えて、スコープを定義する必要があります。

以下のように入力します。 スコープ名access_as_user
同意できるのはだれですか?管理者とユーザー
管理者の同意の表示名Access msal-react-spa
管理者の同意の説明Allows the app to access msal-react-spa as the signed-in user.
ユーザーの同意の表示名Access msal-react-spa
ユーザーの同意の説明Allow the application to access msal-react-spa on your behalf.
状態有効

入力したら、 スコープの追加 をクリックします。

スコープの追加

結果、api://アプリケーションID/access_as_user が世界の誰とも重複しないスコープ名になります。


11.
左側から API のアクセス許可 をクリックして、アプリケーションに必要な API へのアクセス許可を追加するページを開きます。
Microsoft Graph API への User.Read アクセス許可設定は、デフォルトで追加されていますので、そのままにします。

クライアント(React)から自分のAPI へアクセスをできるようにします。

Microsoft Graph API への User.Read スコープ(ユーザー情報取得)のアクセスは最初から登録されていて、最初からクライアント(React)からアクセスできるようになっているということです。

アクセス許可の追加 をクリックします。

アクセス許可の追加


自分の API をクリックします。

自分の API


msal-react-spa をクリックします。

msal-react-spaをクリック


アプリケーションに必要なアクセス許可の種類:委任されたアクセス許可
とし、アクセス許可:access_as_user Access msal-react-spa にチェックを入れて、アクセス許可の追加 をクリックします。

アクセス許可の追加


12.
左側から マニフェスト をクリックして、 "accessTokenAcceptedVersion": null,"accessTokenAcceptedVersion": 2, に変更後、保存 をクリックします。

https://login.microsoftonline.com//oauth2/v2.0/ を使うから、2 です。

マニフェスト


デプロイ

本家チュートリアルでは、デプロイの前に App/src/.env の変更手順がありますが、.env が commit されないため、その手順は、スキップします。

環境変数は、後で設定します。


前提 の通り、 Azure-Samples/ms-identity-javascript-react-tutorial4-Deployment/2-deploy-static のソースコード群が D:\sample に配置済みとします。(配置場所はどこでも良いです。)

ソースコード群配置済み


1.
App フォルダ内で、VS Code を開いて、ソース管理リポジトリを初期化する をクリックします。

VS Code


ソース管理 リポジトリを初期化する


initial commitのようにコミットメッセージを入力して、コミットをクリックします。

コミットをクリック


2.
App フォルダ内で、VS Code を開いて、AzureSign in to Azure... をクリックして、Azure にサインインします。(既にサブスクリプションが表示されている場合は、サインインしていますので、不要です。)

Sign in to Azure


3.
Create ResourceCreate Static Web App... をクリックします。 Create Resource


Create Static Web App


GitHub と連携していない場合、GitHub へのサインインが行われます。 GitHubと連携1
GitHubと連携2
GitHubと連携3
GitHubと連携4


Web アプリ名を入力し、エンターキーを押します。(以降同様に、入力後、エンターキーが必要です。) Webアプリ名を入力


GitHub リポジトリ名を入力します。(この名前で push されます。) GitHubリポジトリ名を入力


リージョンを選択します。(任意) リージョンを選択


React を選択します。 Reactを選択


/ を入力します。 / を入力


build を入力します。 build を入力


4.
GitHub にリポジトリが作成されて、ソースコード群が push されます。
push がトリガーとなり、GitHub Actions が起動して、Azure Static Web Apps への自動デプロイが開始されます。
https://github.com/<github account>/react-test-spa/actions で状況確認ができます。

Azure Static Web Apps への自動デプロイ1


Azure Static Web Apps への自動デプロイ2


Azure Static Web Apps への自動デプロイ3


静的 Web アプリ → react-test-spa にてデプロイされた URL が確認できます。

静的 Webアプリ


デプロイされた URL


アプリの登録 更新

正式な URL が分かったため、アプリの登録を更新します。


1.
Azure ポータル(https://portal.azure.com/)にアクセスして、Azure Active Directory をクリックします。

Azure Active Directory をクリック


2.
左側から アプリの登録 をクリックします。


3.
登録済みアプリの msal-react-spa をクリックします。

登録済みアプリのmsal-react-spaをクリック


4.
左側 ブランド化とプロパティ から、ホーム ページ URL に デプロイしたアプリの URL を入力して、保存 をクリックします。(例:https://reactspa1.z22.web.core.windows.net/

URLは、以下の部分です。

デプロイされた URL

ブランド化とプロパティ


5.

左側 認証 をクリックして、リダイレクト URI に デプロイしたアプリの URL を追加して、保存 をクリックします。

リダイレクト URI


環境変数の登録

1.
Azure ポータル(https://portal.azure.com/)にアクセスして、静的 Web アプリ をクリックします。

静的 Web アプリ


2.
作成したアプリ react-test-spa をクリックします。

作成したアプリreact-test-spaをクリック


3.

左側から 構成 をクリックして、アプリケーション設定追加 にて、以下の環境変数を追加していきます。


CLIENT_ID: b2b9de9e-****-****-****-************
アプリの登録 → msal-react-spa → 概要の アプリケーション (クライアント) ID です。
TENANT_INFO: 2670387a-****-****-****-************
アプリの登録 → msal-react-spa → 概要の ディレクトリ (テナント) ID です。
CLIENT_SECRET: S_a8Q~s*********************************
クライアントシークレットで表示された です。(シークレット ID ではありません。
EXPECTED_SCOPES: access_as_user
API の公開で設定したスコープ名です。(access_as_userで良いです。)


構成 アプリケーション設定


追加したら、保存 をクリックします。

これは、APIが参照する環境変数です。(画面側は、参照してなく、Staticのため、即時反映されず、今設定しても無意味です。)

APIが参照する環境変数

この手順は、本家のチュートリアルに無いのですが、(本家の方は、.env を設定していますが、この手順では push されません。)React をビルドするときの環境変数を設定します。


GitHub のリポジトリへアクセスして、SettingsSecretsActions をクリックします。

New repository secret から


REACT_APP_AAD_APP_CLIENT_ID=b2b9de9e-****-****-****-************
アプリの登録 → msal-react-spa → 概要の アプリケーション (クライアント) ID です。
REACT_APP_AAD_APP_TENANT_ID=2670387a-****-****-****-************
アプリの登録 → msal-react-spa → 概要の ディレクトリ (テナント) ID です。
REACT_APP_AAD_APP_REDIRECT_URI=https://mango-water-******************************
アプリの登録 → msal-react-spa → 認証のリダイレクト URI です。
REACT_APP_AAD_APP_FUNCTION_SCOPE_URI=api://b2b9de9e-****-****-****-************
API の公開で設定したスコープ URI です。/access_as_userはソースコードに書かれているため、/access_as_user無しで設定します。


を設定していきます。

New repository secret1


New repository secret2


New repository secret3


設定し終わったら、VS Code の AzureStatic Web Appsreact-test-spa のところで、右クリックして、Edit Workflow... をクリックします。

Edit Workflow

name: Build and Deploy Job のところに、以下を追記します。

env:
  REACT_APP_AAD_APP_CLIENT_ID: ${{ secrets.REACT_APP_AAD_APP_CLIENT_ID }}
  REACT_APP_AAD_APP_TENANT_ID: ${{ secrets.REACT_APP_AAD_APP_TENANT_ID }}
  REACT_APP_AAD_APP_REDIRECT_URI: ${{ secrets.REACT_APP_AAD_APP_REDIRECT_URI }}
  REACT_APP_AAD_APP_FUNCTION_SCOPE_URI: ${{ secrets.REACT_APP_AAD_APP_FUNCTION_SCOPE_URI }}

env:追加


上書き保存して、ソース管理コミットしてプッシュ でリポジトリへ push します。 そうすると、再度ビルドが動き、上記で設定した環境変数が反映されます。

コミットしてプッシュ

画面側(React)が参照する環境変数です。(Staticのため、ビルドするときに反映されます。)

画面側(React)が参照する環境変数

ビルド完了

終わったら、いよいよ動作確認に入れます。


動作確認

Sign in をクリックします。
Sign in using Popup(ポップアップがログイン画面) または、Sign in using Redirect(画面全体がログイン画面) をクリックします。(どちらでも良いですが、ポップアップの方は、ポップアップを許可する必要があるかもしれません。)

動作確認1


動作確認2


動作確認3


動作確認4


動作確認5


動作確認6


動作確認7


ちなみにですが、デプロイ先のテナントとアカウントとアプリ登録先のテナントは、別々のものでも動作します。(その場合、デプロイ先のテナントのアカウントではサインインできません。)

loading...