ホストされている ASP.NET Core Blazor WebAssembly アプリを Microsoft Entra ID でセキュリティ保護する
この記事では、認証用に Microsoft Entra ID (ME-ID) を使用するホステッド Blazor WebAssembly ソリューションを作成する方法について説明します。 この記事では、シングル テナント Azure アプリ登録を使用したシングル テナント アプリに焦点を当てます。
この記事では、マルチテナント ME-ID の登録については説明しません。 詳しくは、「アプリケーションのマルチテナント化」を参照してください。
この記事では、「クイックスタート: テナントを設定する」で説明されているように、Microsoft Entra テナントの使用に焦点を当てています。 「チュートリアル: Azure Active Directory B2C テナントの作成」で説明されているようにアプリを Azure Active Directory B2C テナントに登録していても、この記事のガイダンスに従うと、ME-ID によるアプリ ID URI の管理は異なる方法で行われます。 詳細については、この記事の「Azure Active Directory B2C テナントの使用」セクションを参照してください。
この記事を読んだ後の追加のセキュリティ シナリオの説明については、「ASP.NET Core Blazor WebAssembly のセキュリティに関するその他のシナリオ」を参照してください。
チュートリアル
このチュートリアルのサブセクションでは、次の方法について説明します。
- Azure でテナントを作成する
- Azure でサーバー API アプリを登録する
- Azure でクライアント アプリを登録する
- Blazor アプリを作成する
- Server
appsettings.json
構成を変更する - 既定のアクセス トークン スコープ スキームを変更する
- アプリを実行する
Azure でテナントを作成する
「クイックスタート: テナントを設定する」のガイダンスに従って、ME-ID でテナントを作成します。
Azure でサーバー API アプリを登録する
サーバー API アプリ用の ME-ID アプリを登録します。
- Azure portal で [Microsoft Entra ID] に移動します。 サイドバーで [アプリケーション]>[アプリの登録] を選択します。 [新規登録] ボタンを選択します。
- アプリの名前を指定します (例: Blazor Server ME-ID)。
- [サポートされているアカウントの種類] を選択します。 このエクスペリエンスでは、 [この組織のディレクトリ内のアカウントのみ] (シングル テナント) を選択できます。
- "サーバー API アプリ" の場合、このシナリオでは [リダイレクト URI] は必要ないので、[プラットフォームの選択] ドロップダウン リストは選択しないままにし、リダイレクト URI は入力しないでください。
- この記事では、アプリが Microsoft Entra ID テナントに登録されていることを前提としています。 アプリが Azure Active Directory B2C テナントに登録されている場合は、[アクセス許可]>[openid と offline_access アクセス許可に対して管理者の同意を付与します] チェック ボックスが表示され、選択されています。 このチェックボックスの選択を解除して、設定を無効にします。 Active Azure Directory テナントを使用している場合、このチェック ボックスは表示されません。
- [登録] を選択します。
次の情報を記録しておきます。
- "サーバー API アプリ" のアプリケーション (クライアント) ID (例:
00001111-aaaa-2222-bbbb-3333cccc4444
) - ディレクトリ (テナント) ID (例:
aaaabbbb-0000-cccc-1111-dddd2222eeee
) - ME-ID プライマリ、パブリッシャー、テナント ドメイン (
contoso.onmicrosoft.com
など): ドメインは、Azure portal で登録されているアプリに対する [ブランド] ブレードのパブリッシャー ドメインとして使用できます。
[API のアクセス許可] で、[Microsoft Graph]>[User.Read] アクセス許可を削除します。サーバー API アプリでは、単にユーザーにサインインし、サーバー API エンドポイントを呼び出すための追加の API アクセスは必要ないためです。
[API の公開] で:
api://{SERVER API APP CLIENT ID}
の形式でアプリ ID URI を確定または追加します。- [Scope の追加] を選択します。
- [Save and continue](保存して続行) を選択します。
- [スコープ名] を指定します (例:
API.Access
)。 - [管理者の同意の表示名] を指定します (例:
Access API
)。 - [管理者の同意の説明] を指定します (例:
Allows the app to access server app API endpoints.
)。 - [状態] が [有効] に設定されていることを確認します。
- [スコープの追加] を選択します。
次の情報を記録しておきます。
- アプリ ID URI GUID (たとえば、
api://00001111-aaaa-2222-bbbb-3333cccc4444
のアプリ ID URI からのレコード00001111-aaaa-2222-bbbb-3333cccc4444
) - スコープ名 (例:
API.Access
)
重要
アプリ ID URI にカスタム値を使用する場合は、Blazor WebAssembly プロジェクト テンプレートからアプリを作成した後、Server アプリと Client アプリの両方に対して構成の変更が必要です。 詳細については、「カスタム アプリ ID URI の使用」セクションを参照してください。
Azure でクライアント アプリを登録する
クライアント アプリ用の ME-ID アプリを登録します。
- Azure portal で [Microsoft Entra ID] に移動します。 サイドバーで [アプリの登録] を選択します。 [新規登録] ボタンを選択します。
- アプリの名前を指定します (例: Blazor クライアント ME-ID)。
- [サポートされているアカウントの種類] を選択します。 このエクスペリエンスでは、 [この組織のディレクトリ内のアカウントのみ] (シングル テナント) を選択できます。
- [リダイレクト URI] ドロップダウン リストを [シングルページ アプリケーション (SPA)] に設定し、次のリダイレクト URI を指定します:
https://localhost/authentication/login-callback
。 Azure の既定のホスト (たとえばazurewebsites.net
) またはカスタム ドメイン ホスト (たとえばcontoso.com
) の運用リダイレクト URI がわかっている場合は、localhost
リダイレクト URI を提供するのと同時に運用リダイレクト URI を追加することもできます。 追加する運用リダイレクト URI には、ポート:443
以外のポートのポート番号を必ず含めてください。 - この記事では、アプリが Microsoft Entra ID テナントに登録されていることを前提としています。 アプリが Azure Active Directory B2C テナントに登録されている場合は、[アクセス許可]>[openid と offline_access アクセス許可に対して管理者の同意を付与します] チェック ボックスが表示され、選択されています。 このチェックボックスの選択を解除して、設定を無効にします。 Active Azure Directory テナントを使用している場合、このチェック ボックスは表示されません。
- [登録] を選択します。
Note
localhost
ME-ID リダイレクト URI のポート番号を指定する必要はありません。 詳細については、「リダイレクト URI (応答 URL) に関する制約と制限」の「Localhost 例外」(Entra ドキュメント) を参照してください。
Client アプリのアプリケーション (クライアント) ID を記録しておきます (例: 11112222-bbbb-3333-cccc-4444dddd5555
)。
[認証]>[プラットフォーム構成]>[シングルページ アプリケーション] で次のようにします。
- リダイレクト URI が
https://localhost/authentication/login-callback
であることを確認します。 - [暗黙的な許可] セクションで、[アクセス トークン] と [ID トークン] のチェックボックスが選択されていないことを確認します。 暗黙的な許可は、MSAL v2.0 以降が使用されている Blazor アプリにはお勧めしていません。 詳しくは、「ASP.NET Core Blazor WebAssembly をセキュリティで保護する」をご覧ください。
- アプリの残りの既定値は、このエクスペリエンスで使用可能です。
- 変更を加えた場合は、[保存] ボタンを選択します。
[API のアクセス許可] で:
- アプリに Microsoft Graph>User.Read アクセス許可があることを確認します。
- [アクセス許可の追加] を選択し、 [自分の API] を選択します。
- [名前] 列でサーバー API アプリを選択します (例: Blazor Server ME-ID)。 Azure portal の [マイ API] 領域にこの API を表示するには、アプリ登録の (API アプリが別個のアプリである場合は API アプリ登録についても) 所有者である必要があります。 詳細については、「アプリケーション所有者を割り当てる (Microsoft Entra ドキュメント)」を参照してください。
- [API] の一覧を開きます。
- API へのアクセスを有効にします (例:
API.Access
)。 - [アクセス許可の追加] を選択します.
- [<テナント名> に管理者の同意を与えます] ボタンを選択します。 [はい] を選択して確定します。
重要
アプリの使用に対する同意がユーザーに委任されたため、API アクセス許可の構成の最後の手順でテナントに管理者の同意を付与する権限を持っていなかった場合は、次の追加の手順を実行する必要があります。
- アプリでは、信頼された発行元ドメインを使用する必要があります。
- Azure portal の
Server
アプリの構成で、[API の公開] を選択します。 [認可済みのクライアント アプリケーション] で、[クライアント アプリケーションの追加] ボタンを選択します。Client
アプリのアプリケーション (クライアント) ID を追加します (例:11112222-bbbb-3333-cccc-4444dddd5555
)。
Blazor アプリを作成する
空のフォルダーで、次のコマンドのプレースホルダーを、前に記録した情報に置き換え、コマンド シェルでこのコマンドを実行します。
dotnet new blazorwasm -au SingleOrg --api-client-id "{SERVER API APP CLIENT ID}" --app-id-uri "{SERVER API APP ID URI GUID}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {PROJECT NAME} --tenant-id "{TENANT ID}"
警告
OIDC アプリ識別子の形成を妨げるダッシュ (-
) をアプリ名 {PROJECT NAME}
に使用しないでください。 Blazor WebAssembly プロジェクト テンプレート内のロジックでは、ソリューションの構成内の OIDC アプリ識別子にプロジェクト名を使用します。 パスカル ケース (BlazorSample
) またはアンダースコア (Blazor_Sample
) は許容可能な代替手段です 詳細については、ホストされた Blazor WebAssembly プロジェクト名に含まれるダッシュによって OIDC のセキュリティが破られる (dotnet/aspnetcore #35337)を参照してください。
プレースホルダー | Azure portal での名前 | 例 |
---|---|---|
{PROJECT NAME} |
— | BlazorSample |
{CLIENT APP CLIENT ID} |
Client アプリのアプリケーション (クライアント) ID | 11112222-bbbb-3333-cccc-4444dddd5555 |
{DEFAULT SCOPE} |
スコープ名 | API.Access |
{SERVER API APP CLIENT ID} |
"サーバー API アプリ" のアプリケーション (クライアント) ID | 00001111-aaaa-2222-bbbb-3333cccc4444 |
{SERVER API APP ID URI GUID} |
アプリケーション ID の URI GUID | 00001111-aaaa-2222-bbbb-3333cccc4444 (GUID のみ、{SERVER API APP CLIENT ID} に一致) |
{TENANT DOMAIN} |
プライマリ、パブリッシャー、テナント ドメイン | contoso.onmicrosoft.com |
{TENANT ID} |
ディレクトリ (テナント) ID | aaaabbbb-0000-cccc-1111-dddd2222eeee |
-o|--output
オプションで指定した出力場所にプロジェクト フォルダーが存在しない場合は作成されて、プロジェクトの名前の一部になります。 OIDC アプリ識別子の形成を妨げるダッシュ (-
) をアプリ名に使用しないでください (前述の警告を参照)。
重要
アプリ ID URI にカスタム値を使用する場合は、Blazor WebAssembly プロジェクト テンプレートからアプリを作成した後、Server アプリと Client アプリの両方に対して構成の変更が必要です。 詳細については、「カスタム アプリ ID URI の使用」セクションを参照してください。
アプリを実行する
Server
プロジェクトからアプリを実行します。 Visual Studio を使用しているときは、次のいずれかを行います。
[実行] ボタンの横にあるドロップダウン矢印を選択します。 ドロップダウン リストから [Configure Startup Projects] (スタートアップ プロジェクトの構成) を開きます。 [シングル スタートアップ プロジェクト] オプションを選択します。 スタートアップ プロジェクトのプロジェクトを確認するか、
Server
プロジェクトに変更します。次のいずれかの方法でアプリを起動する前に、
Server
プロジェクトがソリューション エクスプローラーで強調表示されていることを確認します。- [実行] ボタンを選択します。
- メニューの、 [デバッグ]>[デバッグ開始] を使用します。
- F5キーを押します。
コマンド シェルで、ソリューションの
Server
プロジェクト フォルダーに移動します。dotnet watch
(またはdotnet run
) コマンドを実行します。
User.Identity.Name
を構成する
"このセクションのガイダンスでは、必要に応じて name
要求の値を User.Identity.Name
に設定する方法について説明します。"
Server アプリ API は、http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
クレーム タイプ (bbbb0000-cccc-1111-dddd-2222eeee3333@contoso.onmicrosoft.com
など) の値を User.Identity.Name
に入力します。
name
要求の種類から値を受け取るようにアプリを構成するために、以下のようにします。
Program
ファイルに Microsoft.AspNetCore.Authentication.JwtBearer の名前空間を追加します。using Microsoft.AspNetCore.Authentication.JwtBearer;
JwtBearerOptions の TokenValidationParameters.NameClaimType を構成します。
builder.Services.Configure<JwtBearerOptions>( JwtBearerDefaults.AuthenticationScheme, options => { options.TokenValidationParameters.NameClaimType = "name"; });
ソリューションの各パーツ
このセクションでは、Blazor WebAssembly プロジェクト テンプレートから生成されたソリューションの各部分について説明し、そのソリューションの Client および Server プロジェクトを参照用に構成する方法について説明します。 「チュートリアル」セクションのガイダンスを使用してアプリを作成した場合、基本的な作業アプリケーションについては、このセクションに従う必要がある具体的なガイダンスはありません。 このセクションのガイダンスは、ユーザーの認証と承認を行うためにアプリを更新する場合に役立ちます。 ただし、アプリは別の方法で更新することもできます。それには、「チュートリアル」セクションに記載のガイダンスに従って新しいアプリを作成し、アプリのコンポーネント、クラス、リソースを新しいアプリに移動してください。
appsettings.json
構成
"このセクションは、ソリューションの Server アプリに関連しています。 "
appsettings.json
ファイルには、アクセス トークンの検証に使用される JWT ベアラー ハンドラーを構成するためのオプションが含まれています。 次の AzureAd
構成セクションを追加します。
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "{TENANT DOMAIN}",
"TenantId": "{TENANT ID}",
"ClientId": "{SERVER API APP CLIENT ID}",
"CallbackPath": "/signin-oidc",
"Scopes": "{SCOPES}"
}
}
例:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "contoso.onmicrosoft.com",
"TenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
"ClientId": "00001111-aaaa-2222-bbbb-3333cccc4444",
"CallbackPath": "/signin-oidc",
"Scopes": "API.Access"
}
}
重要
Server アプリが (既定の形式 api://{SERVER API APP CLIENT ID}
ではなく) ME-ID でカスタム アプリ ID URI を使用するように登録されている場合は、「カスタム アプリ ID URI の使用」セクションを参照してください。 Server および Client アプリの両方で変更を行う必要があります。
認証パッケージ
"このセクションは、ソリューションの Server アプリに関連しています。 "
Microsoft identity プラットフォームでコア Web API ASP.NET 呼び出しを認証および承認するためのサポートは、パッケージによって Microsoft.Identity.Web
提供されます。
Note
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
Blazor WebAssembly テンプレートから作成された、ホストされた Blazor ソリューションの Server アプリには、Microsoft.Identity.Web.UI
パッケージが含まれています。 このパッケージでは、Web アプリでユーザー認証用の UI が追加され、Blazor フレームワークでは使用されません。 ユーザーの認証に Server アプリが直接使われない場合は、Server アプリのプロジェクト ファイルからパッケージ参照を削除しても安全です。
認証サービスのサポート
"このセクションは、ソリューションの Server アプリに関連しています。 "
AddAuthentication
メソッドにより、アプリ内での認証サービスが設定され、JWT ベアラー ハンドラーが既定の認証方法として構成されます。 このメソッドは AddMicrosoftIdentityWebApi 、Microsoft identity プラットフォーム v2.0 で Web API を保護するようにサービスを構成します。 このメソッドでは、認証オプションを初期化するために必要な設定で、アプリの構成の AzureAd
セクションが想定されます。
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));
注意
1 つの認証スキームが登録されると、認証スキームがアプリの既定のスキームとして自動的に使用され、スキームを AddAuthentication に指定、または AuthenticationOptions 経由にする必要はありません。 詳細については、「ASP.NET Core の認証の概要」と ASP.NET Core のお知らせ (aspnet/Announcements #490) を参照してください。
UseAuthentication と UseAuthorization により、次のようになります。
- アプリにより、受信要求のトークンの解析と検証が試みられます。
- 適切な資格情報なしで保護されたリソースへのアクセスを試みた要求は失敗します。
app.UseAuthentication();
app.UseAuthorization();
WeatherForecast コントローラー
"このセクションは、ソリューションの Server アプリに関連しています。 "
WeatherForecast
コントローラー (Controllers/WeatherForecastController.cs
) は、[Authorize]
属性が適用されている保護された API をコントローラーに公開します。 次のことを理解しておくことが重要です。
- この API コントローラーの
[Authorize]
属性は、この API を不正アクセスから保護する唯一のものです。 - Blazor WebAssembly アプリで使用される
[Authorize]
属性は、アプリが正しく動作するにはユーザーを承認する必要がある、というアプリへのヒントとしてのみ機能します。
[Authorize]
[ApiController]
[Route("[controller]")]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class WeatherForecastController : ControllerBase
{
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
...
}
}
wwwroot/appsettings.json
構成
"このセクションは、ソリューションの Client アプリに関連しています。 "
構成は wwwroot/appsettings.json
ファイルによって提供されます。
{
"AzureAd": {
"Authority": "https://login.microsoftonline.com/{TENANT ID}",
"ClientId": "{CLIENT APP CLIENT ID}",
"ValidateAuthority": true
}
}
例:
{
"AzureAd": {
"Authority": "https://login.microsoftonline.com/e86c78e2-...-918e0565a45e",
"ClientId": "11112222-bbbb-3333-cccc-4444dddd5555",
"ValidateAuthority": true
}
}
認証パッケージ
"このセクションは、ソリューションの Client アプリに関連しています。 "
職場または学校アカウント (SingleOrg
) を使用するようにアプリを作成すると、アプリは Microsoft Authentication Library (Microsoft.Authentication.WebAssembly.Msal
) のパッケージ参照を自動的に受け取ります。 このパッケージには、アプリでユーザーを認証し、保護された API を呼び出すためのトークンを取得するのに役立つ一連のプリミティブが用意されています。
アプリに認証を追加する場合は、アプリに Microsoft.Authentication.WebAssembly.Msal
パッケージを手動で追加します。
Note
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
Microsoft.Authentication.WebAssembly.Msal
パッケージによって、Microsoft.AspNetCore.Components.WebAssembly.Authentication
パッケージがアプリに推移的に追加されます。
認証サービスのサポート
"このセクションは、ソリューションの Client アプリに関連しています。 "
Server アプリへの要求を行うときのアクセス トークンが含まれる HttpClient インスタンスのサポートが追加されます。
Program
ファイルで次の操作を行います。
builder.Services.AddHttpClient("{PROJECT NAME}.ServerAPI", client =>
client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("{PROJECT NAME}.ServerAPI"));
{PROJECT NAME}
プレースホルダーは、ソリューション作成時のプロジェクト名です。 たとえば、プロジェクト名として BlazorSample
を指定すると、BlazorSample.ServerAPI
の名前付きの HttpClient が生成されます。
ユーザーの認証に対するサポートは、Microsoft.Authentication.WebAssembly.Msal
パッケージによって提供される AddMsalAuthentication 拡張メソッドを使用して、サービス コンテナーに登録されます。 このメソッドでは、アプリが IdentityID プロバイダー (IP) とやり取りするために必要なサービスが設定されます。
Program
ファイルで次の操作を行います。
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});
AddMsalAuthentication メソッドでは、アプリを認証するために必要なパラメーターを構成するためのコールバックを受け入れます。 アプリを構成するために必要な値は、アプリを登録するときに Azure Portal の ME-ID の構成から取得できます。
アクセス トークン スコープ
"このセクションは、ソリューションの Client アプリに関連しています。 "
既定のアクセス トークン スコープでは、次のようなアクセス トークン スコープの一覧が表されます。
- サインイン要求に含まれます。
- 認証直後にアクセス トークンをプロビジョニングするために使用されます。
Program
ファイルには、必要に応じて他のスコープを追加することができます。
builder.Services.AddMsalAuthentication(options =>
{
...
options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});
AdditionalScopesToConsent
を使用して追加のスコープを指定します。
options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");
Note
ユーザーが最初に Microsoft Azure に登録されたアプリを使用する場合、Microsoft Entra ID 同意 UI を介して Microsoft Graph の委任されたユーザーアクセス許可を AdditionalScopesToConsent でプロビジョニングすることはできません。 詳細については、「ASP.NET Core Blazor WebAssembly での Graph API の使用」を参照してください。
既定のアクセス トークン スコープの例:
options.ProviderOptions.DefaultAccessTokenScopes.Add(
"api://00001111-aaaa-2222-bbbb-3333cccc4444/API.Access");
詳細については、"その他のシナリオ" に関する記事の次のセクションを参照してください。
ログイン モード
"このセクションは、ソリューションの Client アプリに関連しています。 "
フレームワークは、既定ではポップアップ ログイン モードになり、ポップアップを開くことができない場合はリダイレクト ログイン モードに戻ります。 MsalProviderOptions の LoginMode
プロパティを redirect
に設定して、リダイレクト ログイン モードを使用するように MSAL を構成します。
builder.Services.AddMsalAuthentication(options =>
{
...
options.ProviderOptions.LoginMode = "redirect";
});
既定の設定は popup
であり、文字列の値の大文字と小文字は区別されません。
インポート ファイル
"このセクションは、ソリューションの Client アプリに関連しています。 "
Microsoft.AspNetCore.Components.Authorization 名前空間は、_Imports.razor
ファイルを介してアプリ全体で使用できるようになります。
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using {APPLICATION ASSEMBLY}
@using {APPLICATION ASSEMBLY}.Shared
Index ページ
"このセクションは、ソリューションの Client アプリに関連しています。 "
Index ページ (wwwroot/index.html
) ページには、JavaScript で AuthenticationService
を定義するスクリプトが含まれています。 AuthenticationService
によって、OIDC プロトコルの下位レベルの詳細が処理されます。 アプリは、認証操作を実行するために、スクリプトで定義されているメソッドを内部的に呼び出します。
<script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>
アプリ コンポーネント
"このセクションは、ソリューションの Client アプリに関連しています。 "
App
コンポーネント (App.razor
) は、Blazor Server アプリにある App
コンポーネントに似ています。
- CascadingAuthenticationState コンポーネントによって、アプリの rest に AuthenticationState を公開する動作が管理されます。
- AuthorizeRouteView コンポーネントによって、現在のユーザーには所与のページへのアクセスが許可されます。それ以外では、
RedirectToLogin
コンポーネントがレンダリングされます。 RedirectToLogin
コンポーネントによって、承認されていないユーザーのログイン ページへのリダイレクトが管理されます。
ASP.NET Core のリリースごとにフレームワークに違いがあるため、App
コンポーネント (App.razor
) の Razor マークアップは、このセクションでは説明しません。 特定のリリース向けのコンポーネントのマークアップを調べる場合は、次の方法の ''いずれか'' を使用してください。
使用しようとしている ASP.NET Core のバージョン向けの既定の Blazor WebAssembly プロジェクト テンプレートから、認証のためにプロビジョニングされたアプリを作成します。 作成されたアプリで、
App
コンポーネント (App.razor
) を検証します。参照元 で、
App
コンポーネント (App.razor
) を検証します。 ブランチ セレクターからバージョンを選択し、リポジトリのProjectTemplates
フォルダーでコンポーネントを検索します。これは、App
コンポーネントの場所が長年にわたって変更されているためです。Note
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
RedirectToLogin コンポーネント
"このセクションは、ソリューションの Client アプリに関連しています。 "
RedirectToLogin
コンポーネント (RedirectToLogin.razor
) は:
- 承認されていないユーザーのログイン ページへのリダイレクトを管理します。
- ユーザーがアクセスしようとしている現在の URL は、次を使用して認証が成功した場合にそのページに戻ることができるように保持されます。
- .NET 7 以降の ASP.NET Core でのナビゲーション履歴の状態。
- .NET 6 以前の ASP.NET Core でのクエリ文字列。
参照元で、RedirectToLogin
コンポーネントを検証します。 コンポーネントの場所は時間の経過と共に変更されたため、GitHub 検索ツールを使用してコンポーネントを見つけてください。
Note
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
LoginDisplay コンポーネント
"このセクションは、ソリューションの Client アプリに関連しています。 "
LoginDisplay
コンポーネント (LoginDisplay.razor
) は MainLayout
コンポーネント (MainLayout.razor
) でレンダリングされます。このコンポーネントによって次の動作が管理されます。
- 認証されたユーザーの場合:
- 現在のユーザー名が表示されます。
- ASP.NET Core Identity のユーザー プロファイル ページへのリンクが提供されます。
- アプリからログアウトするためのボタンが用意されます。
- 匿名ユーザーの場合:
- 登録するオプションが提供されます。
- ログインするオプションが提供されます。
ASP.NET Core のリリースごとにフレームワークに違いがあるため、LoginDisplay
コンポーネントの Razor マークアップは、このセクションでは説明しません。 特定のリリース向けのコンポーネントのマークアップを調べる場合は、次の方法の ''いずれか'' を使用してください。
使用しようとしている ASP.NET Core のバージョン向けの既定の Blazor WebAssembly プロジェクト テンプレートから、認証のためにプロビジョニングされたアプリを作成します。 作成されたアプリで、
LoginDisplay
コンポーネントを検証します。参照元で、
LoginDisplay
コンポーネントを検証します。 コンポーネントの場所は時間の経過と共に変更されたため、GitHub 検索ツールを使用してコンポーネントを見つけてください。true
と等しいHosted
のテンプレート コンテンツが使用されます。注意
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
認証コンポーネント
"このセクションは、ソリューションの Client アプリに関連しています。 "
Authentication
コンポーネント (Pages/Authentication.razor
) によって生成されるページによって、さまざまな認証ステージを処理するために必要なルートが定義されます。
RemoteAuthenticatorView コンポーネント:
Microsoft.AspNetCore.Components.WebAssembly.Authentication
パッケージによって提供されます。- 認証の各段階における適切なアクションの実行を管理します。
@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action" />
@code {
[Parameter]
public string? Action { get; set; }
}
Note
null 許容参照型 (NRT) と .NET コンパイラの null 状態スタティック分析は、.NET 6 以降の ASP.NET Core でサポートされています。 .NET 6 の ASP.NET Core のリリースより前は、string
型は null 型の指定 (?
) なしで表示されます。
FetchData コンポーネント
"このセクションは、ソリューションの Client アプリに関連しています。 "
FetchData
コンポーネントは次の方法を示します。
- アクセス トークンをプロビジョニングする。
- アクセス トークンを使用して、Server アプリで保護されたリソース API を呼び出す。
@attribute [Authorize]
ディレクティブは、このコンポーネントにアクセスするためにユーザーを承認する必要があることを Blazor WebAssembly の承認システムに示します。 Client
アプリに属性が存在しても、適切な資格情報を使用せずにサーバー上の API が呼び出されるのを防ぐことはできません。 また、Server
アプリは、適切なエンドポイントでそれを正しく保護するために [Authorize]
も使用する必要があります。
IAccessTokenProvider.RequestAccessToken は、API を呼び出すために要求に追加できるアクセス トークンの要求を処理します。 トークンがキャッシュされている場合、またはサービスがユーザーの操作なしで新しいアクセス トークンをプロビジョニングできる場合、トークン要求は成功します。 それ以外の場合、トークン要求は、try-catch
ステートメントでキャッチされた AccessTokenNotAvailableException により失敗します。
要求に含める実際のトークンを取得するには、アプリが tokenResult.TryGetToken(out var token)
を呼び出して、要求が成功したことを確認する必要があります。
要求が成功すると、トークン変数にアクセス トークンが設定されます。 トークンの AccessToken.Value プロパティは、Authorization
要求ヘッダーに含めるリテラル文字列を公開します。
ユーザーの操作なしでトークンをプロビジョニングできず、リクエストが失敗した場合:
- .NET 7 以降の ASP.NET Core: アプリは指定された
AccessTokenResult.InteractionOptions
を使用してAccessTokenResult.InteractiveRequestUrl
に移動し、アクセス トークンを更新できるようにします。 - .NET 6 以前の ASP.NET Core: トークン結果にはリダイレクト URL が含まれます。 この URL に移動すると、認証が成功した後、ユーザーがログイン ページに移動してから、現在のページに戻ります。
@page "/fetchdata"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using {APP NAMESPACE}.Shared
@attribute [Authorize]
@inject HttpClient Http
...
@code {
private WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
try
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
}
Azure Active Directory B2C テナントの使用
「チュートリアル: Azure Active Directory B2C テナントの作成」で説明されているようにアプリを Azure Active Directory B2C テナントに登録していても、この記事のガイダンスに従うと、ME-ID によるアプリ ID URI の管理は異なる方法で行われます。
既存のテナントの種類を確認するには、ME-ID 組織の [概要] の上部にある [テナントの管理] リンクを選択してください。 組織の [テナントの種類] 列の値を調べます。 このセクションの内容は、この記事のガイダンスに従いつつも Azure Active Directory B2C テナントに登録されているアプリに関連するものとなっています。
App ID URI の形式は api://{SERVER API APP CLIENT ID OR CUSTOM VALUE}
に一致するものではなく、https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}
となっています。 この違いは、Client および Server アプリの構成に影響します。
サーバー API アプリの場合は、アプリ設定ファイル (
Audience
) 内にappsettings.json
を設定して、末尾のスラッシュなしで Azure portal によって指定される、アプリの対象ユーザー (アプリ ID URI) と一致させます。"Audience": "https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}"
例:
"Audience": "https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444"
Client
アプリのProgram
ファイルで、サーバー API アプリの対象ユーザーと一致するようにスコープ (アプリ ID URI) の対象ユーザーを設定します。options.ProviderOptions.DefaultAccessTokenScopes .Add("https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}/{DEFAULT SCOPE}");
前のスコープでは、アプリ ID URI または対象ユーザーは、値の
https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}
部分となっています。これには、末尾のスラッシュ (/
) とスコープ名 ({DEFAULT SCOPE}
) は含まれません。例:
options.ProviderOptions.DefaultAccessTokenScopes .Add("https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444/API.Access");
前のスコープでは、アプリ ID URI または対象ユーザーは、値の
https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444
部分となっています。これには、末尾のスラッシュ (/
) とスコープ名 (API.Access
) は含まれません。
カスタム アプリ ID URI の使用
アプリ ID URI がカスタム値の場合は、Client アプリ内の既定のアクセス トークン スコープ URI を手動で更新し、対象ユーザーを Server アプリの ME-ID 構成に追加する必要があります。
重要
api://{SERVER API APP CLIENT ID}
の既定の App ID URI を使用する場合、次の構成は必要ありません。
urn://custom-app-id-uri
のアプリ ID URI と API.Access
のスコープ名の例:
Client アプリの
Program
ファイル内は次のようになっています。options.ProviderOptions.DefaultAccessTokenScopes.Add( "urn://custom-app-id-uri/API.Access");
Server アプリの
appsettings.json
内に、アプリ ID URI のみを含み末尾にスラッシュが付いていないAudience
エントリを追加します。"Audience": "urn://custom-app-id-uri"
トラブルシューティング
ログ機能
Blazor WebAssembly 認証のデバッグまたはトレース ログを有効にするには、記事バージョン セレクターを ASP.NET Core 7.0 以降に設定して、ASP.NET Core Blazor ログの "クライアント側認証ログ" セクションを参照してください。
一般的なエラー
アプリまたは Identity プロバイダー (IP) の構成の誤り
最も一般的なエラーの原因は、構成の誤りです。 以下に例を示します。
- シナリオの要件によっては、権限、インスタンス、テナント ID、テナント ドメイン、クライアント ID、またはリダイレクト URI の欠落または誤りによって、アプリによるクライアントの認証ができなくなります。
- 要求スコープが正しくないと、クライアントはサーバー Web API エンドポイントにアクセスできません。
- サーバー API のアクセス許可が正しくないか、存在しないと、クライアントがサーバー Web API エンドポイントにアクセスできなくなります。
- IP のアプリ登録のリダイレクト URI で構成されているものとは異なるポートでアプリが実行されています。 Microsoft Entra ID と、
localhost
開発テスト アドレスで実行されるアプリにポートは必要ありませんが、アプリのポート構成とアプリが実行されているポートは、localhost
以外のアドレスと一致する必要があることに注意してください。
この記事のガイダンスの構成セクションに、正しい構成の例を示します。 記事の各セクションを慎重に確認して、アプリと IP の構成の誤りを探してください。
構成が正しい場合:
アプリケーション ログを分析します。
ブラウザーの開発者ツールを使用して、クライアント アプリと IP またはサーバー アプリの間のネットワーク トラフィックを確認します。 多くの場合、要求を行った後、IP またはサーバー アプリによって、問題の原因を特定する手掛かりを含む正確なエラー メッセージまたはメッセージがクライアントに返されます。 開発者ツールのガイダンスは、次の記事にあります。
- Google Chrome (Google ドキュメント)
- Microsoft Edge
- Mozilla Firefox (Mozilla ドキュメント)
JSON Web トークン (JWT) が使われている Blazor のリリースの場合は、問題が発生している場所に応じて、クライアントの認証またはサーバー Web API へのアクセスに使われるトークンの内容をデコードします。 詳細については、「JSON Web トークン (JWT) の内容を検査する」を参照してください。
ドキュメント チームは、ドキュメントのフィードバックと記事のバグについては対応します (こちらのページのフィードバック セクションからイシューを作成してください) が、製品サポートを提供することはできません。 アプリのトラブルシューティングに役立つ、いくつかのパブリック サポート フォーラムが用意されています。 次をお勧めします。
上記のフォーラムは、Microsoft が所有または管理するものではありません。
セキュリティで保護されておらず、機密でも社外秘でもない再現可能なフレームワークのバグ レポートについては、ASP.NET Core 製品単位でイシューを作成してください。 問題の原因を徹底的に調査し、パブリック サポート フォーラムのコミュニティの助けを借りてもお客様自身で解決できない場合にのみ、製品単位でイシューを作成してください。 単純な構成の誤りやサードパーティのサービスに関連するユース ケースによって破損した個々のアプリのトラブルシューティングは、製品単位で行うことはできません。 レポートが機密性の高い性質のものである場合や、攻撃者が悪用するおそれのある製品の潜在的なセキュリティ上の欠陥が記述されている場合は、「セキュリティの問題とバグの報告」 (
dotnet/aspnetcore
GitHub リポジトリ) をご覧ください。ME-ID で承認されないクライアント
情報:Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] 承認に失敗しました。 次の要件が満たされていません。DenyAnonymousAuthorizationRequirement:認証済みユーザーが必要です。
ME-ID からのログイン コールバック エラー:
- エラー:
unauthorized_client
- 説明:
AADB2C90058: The provided application is not configured to allow public clients.
このエラーを解決するには:
- Azure portal で、アプリのマニフェストにアクセスします。
allowPublicClient
属性をnull
またはtrue
に設定します。
- エラー:
Cookie とサイト データ
Cookie とサイト データは、アプリが更新されても保持され、テストやトラブルシューティングに影響する可能性があります。 アプリ コードの変更、プロバイダーによるユーザー アカウントの変更、プロバイダー アプリの構成変更を行うときは、次のものをクリアしてください。
- ユーザーのサインインの Cookie
- アプリの Cookie
- キャッシュおよび保存されたサイト データ
残った Cookie とサイト データがテストとトラブルシューティングに影響しないようにする方法を、次に示します。
- ブラウザーを構成する
- ブラウザーが閉じるたびに cookie とサイト データをすべて削除するように構成できることをテストするために、ブラウザーを使用します。
- アプリ、テスト ユーザー、プロバイダー構成が変更されるたびにブラウザーが手動で、または IDE によって閉じられていることを確認します。
- カスタム コマンドを使用して、Visual Studio でブラウザーを InPrivate または Incognito モードで開きます:
- Visual Studio の [実行] ボタンをクリックして [ブラウザーの選択] ダイアログボックスを開きます。
- [追加] ボタンを選びます。
- [プログラム] フィールドでブラウザーのパスを指定します。 次の実行可能パスが、Windows 10 の一般的なインストール場所です。 ブラウザーが別の場所にインストールされている場合、または Windows 10 を使用していない場合は、ブラウザーの実行可能ファイルのパスを指定してください。
- Microsoft Edge:
C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
- Google Chrome:
C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
- Mozilla Firefox:
C:\Program Files\Mozilla Firefox\firefox.exe
- Microsoft Edge:
- [引数] フィールドに、ブラウザーを InPrivate または Incognito モードで開くために使用するコマンドライン オプションを指定します。 ブラウザーによっては、アプリの URL が必要になる場合があります。
- Microsoft Edge:
-inprivate
を使用してください。 - Google Chrome:
--incognito --new-window {URL}
を使用します。プレースホルダー{URL}
は開く URL (たとえば、https://localhost:5001
など) です。 - Mozilla Firefox:
-private -url {URL}
を使用します。プレースホルダー{URL}
は開く URL (たとえば、https://localhost:5001
など) です。
- Microsoft Edge:
- [フレンドリ名] フィールドに名前を指定します。 たとえば、
Firefox Auth Testing
のようにします。 - [OK] ボタンを選択します。
- アプリでテストを繰り返すたびにブラウザー プロファイルを選択する必要がないようにするには、 [既定値として設定] ボタンでプロファイルを既定値として設定します。
- アプリ、テスト ユーザー、またはプロバイダー構成が変更されるたびに、ブラウザーが IDE によって閉じられていることを確認します。
アプリのアップグレード
開発マシンで .NET Core SDK をアップグレードしたり、アプリ内のパッケージ バージョンを変更したりした直後に、機能しているアプリが失敗することがあります。 場合によっては、パッケージに統一性がないと、メジャー アップグレード実行時にアプリが破壊されることがあります。 これらの問題のほとんどは、次の手順で解決できます。
- コマンド シェルから
dotnet nuget locals all --clear
を実行して、ローカル システムの NuGet パッケージ キャッシュをクリアします。 - プロジェクトのフォルダー
bin
とobj
を削除します。 - プロジェクトを復元してリビルドします。
- アプリを再展開する前に、サーバー上の展開フォルダー内のすべてのファイルを削除します。
Note
アプリのターゲット フレームワークと互換性のないパッケージ バージョンの使用はサポートされていません。 パッケージの詳細については、NuGet ギャラリーまたは FuGet パッケージ エクスプローラーを使用してください。
Server
アプリを実行する
ホステッド Blazor WebAssemblyソリューションのテストとトラブルシューティングを行うときは、Server
プロジェクトからアプリを実行していることをご確認ください。
ユーザーを検査する
次の User
コンポーネントは、アプリ内で直接使うことも、さらにカスタマイズするための基礎として使うこともできます。
User.razor
:
@page "/user"
@attribute [Authorize]
@using System.Text.Json
@using System.Security.Claims
@inject IAccessTokenProvider AuthorizationService
<h1>@AuthenticatedUser?.Identity?.Name</h1>
<h2>Claims</h2>
@foreach (var claim in AuthenticatedUser?.Claims ?? Array.Empty<Claim>())
{
<p class="claim">@(claim.Type): @claim.Value</p>
}
<h2>Access token</h2>
<p id="access-token">@AccessToken?.Value</p>
<h2>Access token claims</h2>
@foreach (var claim in GetAccessTokenClaims())
{
<p>@(claim.Key): @claim.Value.ToString()</p>
}
@if (AccessToken != null)
{
<h2>Access token expires</h2>
<p>Current time: <span id="current-time">@DateTimeOffset.Now</span></p>
<p id="access-token-expires">@AccessToken.Expires</p>
<h2>Access token granted scopes (as reported by the API)</h2>
@foreach (var scope in AccessToken.GrantedScopes)
{
<p>Scope: @scope</p>
}
}
@code {
[CascadingParameter]
private Task<AuthenticationState> AuthenticationState { get; set; }
public ClaimsPrincipal AuthenticatedUser { get; set; }
public AccessToken AccessToken { get; set; }
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
var state = await AuthenticationState;
var accessTokenResult = await AuthorizationService.RequestAccessToken();
if (!accessTokenResult.TryGetToken(out var token))
{
throw new InvalidOperationException(
"Failed to provision the access token.");
}
AccessToken = token;
AuthenticatedUser = state.User;
}
protected IDictionary<string, object> GetAccessTokenClaims()
{
if (AccessToken == null)
{
return new Dictionary<string, object>();
}
// header.payload.signature
var payload = AccessToken.Value.Split(".")[1];
var base64Payload = payload.Replace('-', '+').Replace('_', '/')
.PadRight(payload.Length + (4 - payload.Length % 4) % 4, '=');
return JsonSerializer.Deserialize<IDictionary<string, object>>(
Convert.FromBase64String(base64Payload));
}
}
JSON Web トークン (JWT) の内容を検査する
JSON Web トークン (JWT) をデコードするには、Microsoft の jwt.ms ツールを使用します。 UI の値がブラウザーに残ることはありません。
エンコードされた JWT の例 (表示用に短縮されています):
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1j ... bQdHBHGcQQRbW7Wmo6SWYG4V_bU55Ug_PW4pLPr20tTS8Ct7_uwy9DWrzCMzpD-EiwT5IjXwlGX3IXVjHIlX50IVIydBoPQtadvT7saKo1G5Jmutgq41o-dmz6-yBMKV2_nXA25Q
Azure AAD B2C に対して認証するアプリのツールによってデコードされた JWT の例:
{
"typ": "JWT",
"alg": "RS256",
"kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk"
}.{
"exp": 1610059429,
"nbf": 1610055829,
"ver": "1.0",
"iss": "https://mysiteb2c.b2clogin.com/11112222-bbbb-3333-cccc-4444dddd5555/v2.0/",
"sub": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
"aud": "00001111-aaaa-2222-bbbb-3333cccc4444",
"nonce": "bbbb0000-cccc-1111-dddd-2222eeee3333",
"iat": 1610055829,
"auth_time": 1610055822,
"idp": "idp.com",
"tfp": "B2C_1_signupsignin"
}.[Signature]
その他の技術情報
- アプリの発行元ドメインを構成する
- Microsoft Entra ID アプリ マニフェスト: identifierUris 属性
- ASP.NET Core Blazor WebAssembly のセキュリティに関するその他のシナリオ
- Authentication.MSAL JavaScript ライブラリのカスタム バージョンをビルドする
- セキュリティで保護された既定のクライアントを使用する、アプリ内の認証または承認されていない Web API 要求
- Microsoft Entra ID のグループとロール (.NET 5 から .NET 7) を使用した ASP.NET Core Blazor WebAssembly
- ASP.NET Core を使用した Microsoft identity プラットフォームと Microsoft Entra ID
- Microsoft identity プラットフォーム ドキュメント
- クイックスタート: Microsoft identity プラットフォームにアプリケーションを登録する
- Microsoft Entra ID でのアプリケーション プロパティのセキュリティに関するベスト プラクティス
ASP.NET Core