チュートリアル:Azure App Service でユーザーをエンド ツー エンドで認証および承認する
Azure App Service は、非常にスケーラブルな、自己適用型の Web ホスティング サービスを提供します。 さらに、App Service には、ユーザーの認証と承認のためのサポートが組み込まれています。 このチュートリアルでは、App Service の認証と承認を使用してアプリケーションをセキュリティで保護する方法を示します。 例として、ビュー フロントエンドを含む Express.js を使います。 App Service の認証と承認では、すべての言語のランタイムがサポートされています。このチュートリアルに沿って、お好みの言語に適用する方法を学習することができます。
Azure App Service は、Linux オペレーティング システムを使用する、高度にスケーラブルな自己適用型の Web ホスティング サービスを提供します。 さらに、App Service には、ユーザーの認証と承認のためのサポートが組み込まれています。 このチュートリアルでは、App Service の認証と承認を使用してアプリケーションをセキュリティで保護する方法を示します。 ビューを含む Express.js を使います。 App Service の認証と承認では、すべての言語のランタイムがサポートされています。このチュートリアルに沿って、お好みの言語に適用する方法を学習することができます。
このチュートリアルでは、以下の内容を学習します。
- 組み込みの認証および承認を有効にする
- 未認証の要求に対してアプリをセキュリティで保護する
- ID プロバイダーとして Microsoft Entra ID を使用する
- サインインしたユーザーの代わりにリモート アプリにアクセスする
- トークン認証を使用して、サービス間呼び出しをセキュリティで保護する
- サーバー コードのアクセス トークンを使用する
ヒント
このシナリオを完了したら、次の手順に進み、認証ユーザーとして Azure サービスに接続する方法を学習します。 一般的なシナリオには、特定の能力または特定のテーブルやファイルへのアクセス権を持つユーザーとして、Azure Storage またはデータベースにアクセスすることが含まれます。
この手順の認証は、Azure App Service によるホスティング プラットフォーム レイヤーで提供されます。 この Web アプリを問題なく使うには、フロントエンドとバックエンドのアプリをデプロイし、認証を構成する必要があります。
ユーザー プロファイルを取得する
フロントエンド アプリは、セキュリティで保護された方法でバックエンド API を使うように構成されています。 フロントエンド アプリケーションはユーザーに対して Microsoft サインインを提供しており、ユーザーはバックエンドから自分の "偽の" プロファイルを取得できます。 このチュートリアルでは、シナリオを完了する手順を単純化するために偽のプロファイルを使います。
フロントエンド上でソース コードを実行する前に、App Service は App Service x-ms-token-aad-access-token
ヘッダーから認証コード accessToken
を挿入します。 次に、セキュリティで保護された方法でバックエンド API にアクセスするために、フロントエンド ソース コードを使って、bearerToken
として accessToken にアクセスし、バックエンド サーバーに送信します。 バックエンド サーバーは、バックエンド ソース コードに渡す前に、bearerToken を検証します。 バックエンド ソース コードが bearerToken を受け取ると、それを使用できます。
"このシリーズの次の記事" では、bearerToken を Microsoft Graph API にアクセスするためのスコープを持つトークンと交換します。 Microsoft Graph API は、ユーザーのプロファイル情報を返します。
前提条件
Azure サブスクリプションをお持ちでない場合は、開始する前に Azure 無料アカウントを作成してください。
Azure Cloud Shell で Bash 環境を使用します。 詳細については、「Azure Cloud Shell の Bash のクイックスタート」を参照してください。
CLI リファレンス コマンドをローカルで実行する場合、Azure CLI をインストールします。 Windows または macOS で実行している場合は、Docker コンテナーで Azure CLI を実行することを検討してください。 詳細については、「Docker コンテナーで Azure CLI を実行する方法」を参照してください。
ローカル インストールを使用する場合は、az login コマンドを使用して Azure CLI にサインインします。 認証プロセスを完了するには、ターミナルに表示される手順に従います。 その他のサインイン オプションについては、Azure CLI でのサインインに関するページを参照してください。
初回使用時にインストールを求められたら、Azure CLI 拡張機能をインストールします。 拡張機能の詳細については、Azure CLI で拡張機能を使用する方法に関するページを参照してください。
az version を実行し、インストールされているバージョンおよび依存ライブラリを検索します。 最新バージョンにアップグレードするには、az upgrade を実行します。
1. サンプル アプリケーションをクローンする
Azure Cloud Shell で次のコマンドを実行し、サンプル リポジトリをクローンします。
git clone https://github.com/Azure-Samples/js-e2e-web-app-easy-auth-app-to-app
2. アプリを作成してデプロイする
リソース グループ、Web アプリ プラン、Web アプリを作成し、1 つの手順でデプロイします。
フロントエンド Web アプリのディレクトリに移動します。
cd js-e2e-web-app-easy-auth-app-to-app/frontend
az webapp up を使ってフロントエンド Web アプリを作成し、デプロイします。 Web アプリの名前はグローバルに一意である必要があるため、
<front-end-app-name>
を一意の名前に置き換えます。az webapp up --resource-group myAuthResourceGroup --name <front-end-app-name> --plan myPlan --sku FREE --os-type Windows --location "West Europe" --runtime "NODE:16LTS"
バックエンド Web アプリのディレクトリに移動します。
cd ../backend
バックエンド Web アプリを同じリソース グループとアプリ プランにデプロイします。 Web アプリの名前はグローバルに一意である必要があるため、
<back-end-app-name>
を一意のイニシャルまたは数字のセットに置き換えます。az webapp up --resource-group myAuthResourceGroup --name <back-end-app-name> --plan myPlan --os-type Windows --location "West Europe" --runtime "NODE:16LTS"
フロントエンド Web アプリのディレクトリに移動します。
cd frontend
az webapp up を使ってフロントエンド Web アプリを作成し、デプロイします。 Web アプリの名前はグローバルに一意である必要があるため、
<front-end-app-name>
を一意のイニシャルまたは数字のセットに置き換えます。az webapp up --resource-group myAuthResourceGroup --name <front-end-app-name> --plan myPlan --sku FREE --location "West Europe" --os-type Linux --runtime "NODE:16-lts"
バックエンド Web アプリのディレクトリに移動します。
cd ../backend
バックエンド Web アプリを同じリソース グループとアプリ プランにデプロイします。 Web アプリの名前はグローバルに一意である必要があるため、
<back-end-app-name>
を一意のイニシャルまたは数字のセットに置き換えます。az webapp up --resource-group myAuthResourceGroup --name <back-end-app-name> --plan myPlan --sku FREE --location "West Europe" --runtime "NODE:16-lts"
3. アプリケーション設定を構成する
フロントエンド アプリケーションは、API 要求のバックエンド アプリケーションの URL を認識している必要があります。 次の Azure CLI コマンドを使って、アプリの設定を構成します。 URL は、https://<back-end-app-name>.azurewebsites.net
の形式にする必要があります
az webapp config appsettings set --resource-group myAuthResourceGroup --name <front-end-app-name> --settings BACKEND_URL="https://<back-end-app-name>.azurewebsites.net"
4. フロントエンドからバックエンドを呼び出す
フロントエンド アプリを参照し、バックエンドから "偽の" プロファイルを返します。 このアクションを使って、フロントエンドがバックエンドに対してプロファイルを正常に要求していることと、バックエンドがプロファイルを返していることを検証します。
ブラウザーでフロントエンド Web アプリ
https://<front-end-app-name>.azurewebsites.net
を開きます。[
Get user's profile
](ログの一元化) リンクを選択します。バックエンド Web アプリから返された "偽の" プロファイルを確認します。
withAuthentication
の値が false の場合は、認証がまだ設定されて "いない" ことを示します。
5. 認証を構成する
この手順では、2 つの Web アプリの認証と認可を有効にします。 このチュートリアルでは、ID プロバイダーとして Microsoft Entra ID を使用します。
次のようにフロントエンド アプリを構成することもできます。
- フロントエンド アプリにバックエンド アプリへのアクセス権を付与する
- 使用可能なトークンを返すように App Service を構成する
- コードでトークンを使う
詳細については、「App Services アプリケーションの Microsoft Entra 認証を構成する」を参照してください。
バックエンド アプリの認証と認可を有効にする
[Azure portal] メニューで [リソース グループ] を選択するか、または任意のページから [リソース グループ] を検索して選択します。
[リソース グループ] でリソース グループを検索して選択します。 [概要] でバックエンド アプリを選びます。
バックエンド アプリの左側のメニューで [認証] を選び、[ID プロバイダーの追加] を選びます。
[ID プロバイダーの追加] ページで、Microsoft および Microsoft Entra ID にサインインするための ID プロバイダーとして [Microsoft] を選択します。
既定の設定をそのままにして [追加] を選びます。
[認証] ページが開きます。 Microsoft Entra アプリケーションの[クライアント ID をメモ帳にコピーします。 この値は、後で必要になります。
ここで終えた場合でも、既に App Service の認証と承認によってセキュリティが確保された自己完結型のアプリが完成します。 残りのセクションでは、認証済みのユーザーをフロント エンドからバックエンドに "送る" ことによって、マルチアプリ ソリューションのセキュリティを確保する方法について説明します。
フロントエンド アプリの認証と認可を有効にする
[Azure portal] メニューで [リソース グループ] を選択するか、または任意のページから [リソース グループ] を検索して選択します。
[リソース グループ] でリソース グループを検索して選択します。 [概要] でフロントエンド アプリの管理ページを選択します。
フロントエンド アプリの左側のメニューで [認証] を選び、[ID プロバイダーの追加] を選びます。
[ID プロバイダーの追加] ページで、Microsoft および Microsoft Entra ID にサインインするための ID プロバイダーとして [Microsoft] を選択します。
既定の設定をそのままにして [追加] を選びます。
[認証] ページが開きます。 Microsoft Entra アプリケーションの[クライアント ID をメモ帳にコピーします。 この値は、後で必要になります。
フロントエンド アプリにバックエンドへのアクセス権を付与する
両方のアプリに対する認証と承認を有効にしたので、それぞれのアプリは AD アプリケーションによってサポートされています。 認証を完了するには、次の 3 つのことを行う必要があります。
- フロントエンド アプリにバックエンド アプリへのアクセス権を付与する
- 使用可能なトークンを返すように App Service を構成する
- コードでトークンを使う
ヒント
エラーが発生してアプリの認証/承認設定を再構成すると、トークン ストア内のトークンが新しい設定で再生成されないことがあります。 トークンが再生成されるようにするには、サインアウトしてからアプリにサインインし直す必要があります。 そのための簡単な方法は、ブラウザーをプライベート モードで使用し、アプリの設定を変更した後、ブラウザーを閉じてからプライベート モードでもう一度開くことです。
この手順では、ユーザーに代わってフロントエンド アプリにバックエンド アプリへのアクセス権を付与します。 (技術的には、ユーザーの代わりにバックエンドの "AD アプリケーション" にアクセスするためのアクセス許可をフロントエンドの "AD アプリケーション" に付与します)。
フロントエンド アプリの [認証] ページで、[ID プロバイダー] の下からフロントエンド アプリ名を選びます。 このアプリの登録は自動的に生成されました。 左側のメニューから [API のアクセス許可] を選択します。
[アクセス許可の追加] を選択し、[自分の API]><back-end-app-name> を選択します。
バックエンド アプリの [API アクセス許可の要求] ページで、[委任されたアクセス許可] と [user_impersonation] を選び、次に [アクセス許可の追加] を選びます。
使用可能なアクセス トークンを返すように App Service を構成する
これで、フロントエンド アプリに、サインインしたユーザーとしてバックエンド アプリにアクセスするために必要なアクセス許可が与えられました。 この手順では、バックエンドにアクセスするための使用可能なアクセス トークンを提供するように、App Service の認証および認可を構成します。 この手順では、バックエンドのクライアント ID が必要です。この ID は、「バックエンド アプリの認証と認可を有効にする」でコピーしたものです。
Cloud Shell のフロントエンド アプリで次のコマンドを実行して、scope
パラメーターを認証設定 identityProviders.azureActiveDirectory.login.loginParameters
に追加します。 <front-end-app-name> と <back-end-client-id> を置き換えます。
az extension add --name authV2
authSettings=$(az webapp auth show -g myAuthResourceGroup -n <front-end-app-name>)
authSettings=$(echo "$authSettings" | jq '.properties' | jq '.identityProviders.azureActiveDirectory.login += {"loginParameters":["scope=openid offline_access api://<back-end-client-id>/user_impersonation"]}')
az webapp auth set --resource-group myAuthResourceGroup --name <front-end-app-name> --body "$authSettings"
これらのコマンドでは実質的に、カスタム スコープを付加した loginParameters
プロパティが追加されます。 要求するスコープの説明を次に示します。
openid
は、既に既定で App Service によって要求されています。 詳細については、「OpenID Connect のスコープ」を参照してください。- offline_access は、便宜上ここに含まれています (トークンを更新したい場合)。
api://<back-end-client-id>/user_impersonation
は、バックエンド アプリの登録で公開される API です。 これは、バックエンド アプリをトークンの対象ユーザーとして含む JWT トークンが得られるスコープです。
ヒント
- Azure portal で
api://<back-end-client-id>/user_impersonation
スコープを表示するには、バックエンド アプリの [認証] ページに移動し、[ID プロバイダー] の下のリンクをクリックし、左側のメニューの [API の公開] をクリックします。 - 代わりに Web インターフェイスを使用して要求するスコープを構成するには、「認証トークンを更新する」の Microsoft の手順を参照してください。
- スコープによっては、管理者またはユーザーの同意が必要な場合があります。 この要件により、ユーザーがブラウザーでフロントエンド アプリにサインインすると、同意要求ページが表示されます。 この同意ページが表示されないようにするには、[クライアント アプリケーションの追加] をクリックし、フロントエンドのアプリ登録のクライアント ID を指定して、[API の公開] ページで、フロントエンドのアプリ登録を、承認されたクライアント アプリケーションとして追加します。
これでアプリの構成は完了です。 フロントエンドが適切なアクセス トークンを使用してバックエンドにアクセスする準備ができました。
他のプロバイダー用にアクセス トークンを構成する方法については、「ID プロバイダー トークンの更新」を参照してください。
6.フロントエンド App Service からのみトークンを受け入れるようにバックエンド App Service を構成する
フロントエンド App Service からのみトークンを受け入れるようにもバックエンド App Service を構成してください。 これを行わないと、フロントエンドからバックエンドにトークンを渡すとき、"403: アクセス不可エラー" が発生する可能性があります。
これは、前の手順で使用したのと同じ Azure CLI プロセスを使用して設定できます。
フロントエンド App Service の
appId
を取得します (フロントエンド App Service の [認証] ブレードで取得できます)。<back-end-app-name>
と<front-end-app-id>
に置き換えて、次の Azure CLI を実行します。
authSettings=$(az webapp auth show -g myAuthResourceGroup -n <back-end-app-name>)
authSettings=$(echo "$authSettings" | jq '.properties' | jq '.identityProviders.azureActiveDirectory.validation.defaultAuthorizationPolicy.allowedApplications += ["<front-end-app-id>"]')
az webapp auth set --resource-group myAuthResourceGroup --name <back-end-app-name> --body "$authSettings"
authSettings=$(az webapp auth show -g myAuthResourceGroup -n <back-end-app-name>)
authSettings=$(echo "$authSettings" | jq '.properties' | jq '.identityProviders.azureActiveDirectory.validation.jwtClaimChecks += { "allowedClientApplications": ["<front-end-app-id>"]}')
az webapp auth set --resource-group myAuthResourceGroup --name <back-end-app-name> --body "$authSettings"
7.認証されたバックエンドをフロントエンドから呼び出す
フロントエンド アプリは、正しい user_impersonation
スコープを指定してユーザーの認証をバックエンドに渡す必要があります。 以下の手順では、この機能のサンプルで提供されているコードを確認します。
フロントエンド アプリのソース コードを確認します。
フロントエンド App Service が挿入した
x-ms-token-aad-access-token
ヘッダーを使って、ユーザーの accessToken をプログラムで取得します。// ./src/server.js const accessToken = req.headers['x-ms-token-aad-access-token'];
bearerToken
値としてAuthentication
ヘッダーの accessToken を使います。// ./src/remoteProfile.js // Get profile from backend const response = await fetch(remoteUrl, { cache: "no-store", // no caching -- for demo purposes only method: 'GET', headers: { 'Authorization': `Bearer ${accessToken}` } }); if (response.ok) { const { profile } = await response.json(); console.log(`profile: ${profile}`); } else { // error handling }
このチュートリアルでは、シナリオを簡単にするために "偽の" プロファイルを返します。 このシリーズの次のチュートリアルでは、バックエンドの bearerToken を Microsoft Graph などのダウンストリーム Azure サービスのスコープを持つ新しいトークンと交換する方法を示します。
7. バックエンドからフロントエンドにプロファイルを返す
フロントエンドからの要求が認可されていない場合、バックエンド アプリ サービスは、要求がアプリケーション コードに到達する "前に"、401 HTTP エラー コードで要求を拒否します。 バックエンド コードに到達したら (認可されたトークンを含むため)、bearerToken を抽出して accessToken を取得します。
バックエンド アプリのソース コードを確認します。
// ./src/server.js
const bearerToken = req.headers['Authorization'] || req.headers['authorization'];
if (bearerToken) {
const accessToken = bearerToken.split(' ')[1];
console.log(`backend server.js accessToken: ${!!accessToken ? 'found' : 'not found'}`);
// TODO: get profile from Graph API
// provided in next article in this series
// return await getProfileFromMicrosoftGraph(accessToken)
// return fake profile for this tutorial
return {
"displayName": "John Doe",
"withAuthentication": !!accessToken ? true : false
}
}
8. アプリを参照する
ブラウザーでフロントエンド Web サイトを使います。 URL は
https://<front-end-app-name>.azurewebsites.net/
という形式です。ブラウザーから、Web アプリへの認証が要求されます。 認証を完了します。
認証が完了すると、フロントエンド アプリからアプリのホーム ページが返されます。
[
Get user's profile
] を選択します。 これにより、ベアラー トークンの認証がバックエンドに渡されます。バックエンド エンドは、"偽の" ハードコーディングされたプロファイル名
John Doe
で応答します。withAuthentication
の値が true の場合、認証がまだ設定されて "いる" ことを示します。
9.リソースをクリーンアップする
前の手順では、リソース グループ内に Azure リソースを作成しました。
Cloud Shell で次のコマンドを実行して、リソース グループを削除します。 このコマンドの実行には、少し時間がかかる場合があります。
az group delete --name myAuthResourceGroup
認証アプリのクライアント ID を使います。これは、バックエンド アプリとフロントエンド アプリの
Enable authentication and authorization
セクションで以前に確認し、メモしておいたものです。フロントエンド アプリとバックエンド アプリの両方のアプリ登録を削除します。
# delete app - do this for both frontend and backend client ids az ad app delete <client-id>
よく寄せられる質問
この認証をローカルの開発マシンでテストするにはどうすればよいですか?
この手順の認証は、Azure App Service によるホスティング プラットフォーム レイヤーで提供されます。 同等のエミュレーターはありません。 認証を使うには、フロントエンド アプリとバックエンド アプリと、それぞれの構成認証をデプロイする必要があります。
アプリに "偽の" プロファイルが表示されない場合は、どのようにデバッグすればよいですか?
このアプリケーションから "偽の" プロファイルが返されない場合、フロントエンド アプリとバックエンド アプリの両方に認証のデバッグに役立つ /debug
ルートがあります。 フロントエンドのデバッグ ルートは、以下を検証する重要な要素を提供します。
- 環境変数:
BACKEND_URL
はhttps://<back-end-app-name>.azurewebsites.net
として正しく構成されています。 末尾にはスラッシュまたはルートを含めないでください。
- HTTP ヘッダー:
x-ms-token-*
ヘッダーが挿入されます。
- サインインしたユーザーの Microsoft Graph プロファイル名が表示されます。
- フロントエンド アプリのトークンに対するスコープには
user_impersonation
があります。 スコープにこれが含まれていない場合、タイミングの問題である可能性があります。 Azure リソースでフロントエンド アプリのlogin
パラメーターを確認します。 認証がレプリケートされるまで数分待ちます。
アプリケーションのソース コードは各 Web アプリに正しくデプロイされましたか?
Web アプリの Azure portal で、[開発ツール] -> [高度なツール] を選び、[移動] -> を選びます。 これにより、新しいブラウザー タブまたはウィンドウが開きます。
新しいブラウザー タブで、[ディレクトリを参照] -> [Site wwwroot] (サイト wwwroot) を選びます。
ディレクトリに次の項目があることを確認します。
- package.json
- node_modules.tar.gz
- /src/index.js
package.json の
name
プロパティが Web 名と同じfrontend
またはbackend
であることを確認します。ソース コードを変更し、再デプロイする必要がある場合は、そのアプリの package.json ファイルがあるディレクトリから az webapp up を使います。
アプリケーションは正しく起動しましたか
どちらの Web アプリも、ホーム ページが要求されたときに何かを返すはずです。 Web アプリで /debug
に到達できない場合、アプリは正しく起動していません。 その Web アプリのエラー ログを確認します。
- Web アプリの Azure portal で、[開発ツール] -> [高度なツール] を選び、[移動] -> を選びます。 これにより、新しいブラウザー タブまたはウィンドウが開きます。
- 新しいブラウザー タブで、[ディレクトリを参照] -> [デプロイ ログ] を選びます。
- 各ログを確認し、報告された問題を見つけます。
フロントエンド アプリはバックエンド アプリと会話できますか?
フロントエンド アプリはサーバーのソース コードからバックエンド アプリを呼び出すため、ブラウザーのネットワーク トラフィックで確認できるものではありません。 次の一覧を使って、バックエンド プロファイル要求の成功を判断します。
- バックエンド Web アプリは、到達した場合にフロントエンド アプリにあらゆるエラーを返します。 到達しなかった場合、フロントエンド アプリは状態コードとメッセージを報告します。
- 401: ユーザーは認証に正しく合格しませんでした。 これは、スコープが正しく設定されていないことを示している可能性があります。
- 404: サーバーへの URL が、サーバーが持つルートと一致しません
- バックエンド アプリのストリーミング ログを使って、ユーザーのプロファイルに対してフロントエンド要求を行っていることを確認します。
console.log
を含むソース コードにはデバッグ情報があり、どこでエラーが発生したかを特定するのに役立ちます。
フロントエンド トークンの有効期限が切れるとどうなりますか?
アクセス トークンは、しばらくすると有効期限が切れます。 アプリに対する再認証をユーザーに強制することなくアクセス トークンを更新する方法については、「Refresh identity provider tokens (ID プロバイダー トークンの更新)」を参照してください。
フロントエンド アプリにブラウザーベースのアプリがある場合、バックエンドと直接通信できますか?
この手法では、サーバー コードがクライアント ブラウザーで実行されている JavaScript コードにアクセス トークンを渡す必要があります。 ブラウザーでアクセス トークンを保護する方法がないため、これは推奨される手法ではありません。 現時点では、Backend-for-Frontend パターンをお勧めします。 このチュートリアルの例に適用すると、フロントエンド アプリのブラウザー コードは、認証されたセッションでサーバー コードへの API 呼び出しを仲介者として行い、次にフロントエンド アプリのサーバー コードは、x-ms-token-aad-access-token
ヘッダー値をベアラー トークンとして使用してバックエンド アプリへの API 呼び出しを行います。 ブラウザー コードからサーバー コードへのすべての呼び出しは、既に認証されたセッションによって保護されます。
次のステップ
ここで学習した内容は次のとおりです。
- 組み込みの認証および承認を有効にする
- 未認証の要求に対してアプリをセキュリティで保護する
- ID プロバイダーとして Microsoft Entra ID を使用する
- サインインしたユーザーの代わりにリモート アプリにアクセスする
- トークン認証を使用して、サービス間呼び出しをセキュリティで保護する
- サーバー コードのアクセス トークンを使用する
次のチュートリアルに進み、このユーザーの ID を使って Azure サービスにアクセスする方法を学習します。