ホストされている ASP.NET Core Blazor WebAssembly アプリを Identity Server でセキュリティ保護する
この記事では、ユーザーと API 呼び出しの認証に IdentityServer を使用する、ホストされている Blazor WebAssembly ソリューションを作成する方法について説明します。
重要
Duende Software により、Duende Identity Server を実稼働で使用することのライセンス料の支払いが求められる場合があります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。
Note
既存の外部 Identity サーバー インスタンスを使用するように、スタンドアロンの、またはホストされた Blazor WebAssembly アプリを構成するには、「認証ライブラリを使用して、ASP.NET Core Blazor WebAssembly スタンドアロン アプリをセキュリティで保護する」のガイダンスに従ってください。
この記事を読んだ後の追加のセキュリティ シナリオの説明については、「ASP.NET Core Blazor WebAssembly のセキュリティに関するその他のシナリオ」を参照してください。
チュートリアル
このチュートリアルのサブセクションでは、次の方法について説明します。
- Blazor アプリを作成する
- アプリを実行する
Blazor アプリを作成する
認証メカニズムを使用して新しい Blazor WebAssembly プロジェクトを作成するには:
新しいプロジェクトを作成します。
Blazor WebAssembly アプリ テンプレートを選択します。 [次へ] を選択します。
ダッシュを使用せずにプロジェクト名を指定します。 場所が正しいことを確認します。 [次へ] を選択します。
OIDC アプリ識別子の形成を妨げるダッシュ (
-
) をプロジェクト名に使用しないでください。 Blazor WebAssembly プロジェクト テンプレート内のロジックでは、ソリューションの構成内の OIDC アプリ識別子にプロジェクト名を使用します。OIDC アプリ識別子内にダッシュは許可されません。 パスカル ケース (BlazorSample
) またはアンダースコア (Blazor_Sample
) は許容可能な代替手段です[追加情報] ダイアログで、[認証の種類] として [個別のアカウント] を選択し、ASP.NET Core の Identity システムを使用してアプリ内にユーザーを格納します。
[ASP.NET Core hosted](ASP.NET Core ホステッド) チェックボックスをオンにします。
[作成] ボタンを選択してアプリを作成します。
アプリを実行する
Server
プロジェクトからアプリを実行します。 Visual Studio を使用しているときは、次のいずれかを行います。
[実行] ボタンの横にあるドロップダウン矢印を選択します。 ドロップダウン リストから [Configure Startup Projects] (スタートアップ プロジェクトの構成) を開きます。 [シングル スタートアップ プロジェクト] オプションを選択します。 スタートアップ プロジェクトのプロジェクトを確認するか、
Server
プロジェクトに変更します。次のいずれかの方法でアプリを起動する前に、
Server
プロジェクトがソリューション エクスプローラーで強調表示されていることを確認します。- [実行] ボタンを選択します。
- メニューの、 [デバッグ]>[デバッグ開始] を使用します。
- F5キーを押します。
コマンド シェルで、ソリューションの
Server
プロジェクト フォルダーに移動します。dotnet watch
(またはdotnet run
) コマンドを実行します。
ソリューションの各パーツ
このセクションでは、Blazor WebAssembly プロジェクト テンプレートから生成されたソリューションの各部分について説明し、そのソリューションの Client および Server プロジェクトを参照用に構成する方法について説明します。 「チュートリアル」セクションのガイダンスを使用してアプリを作成した場合、基本的な作業アプリケーションについては、このセクションに従う必要がある具体的なガイダンスはありません。 このセクションのガイダンスは、ユーザーの認証と承認を行うためにアプリを更新する場合に役立ちます。 ただし、アプリは別の方法で更新することもできます。それには、「チュートリアル」セクションに記載のガイダンスに従って新しいアプリを作成し、アプリのコンポーネント、クラス、リソースを新しいアプリに移動してください。
Server アプリ サービス
"このセクションは、ソリューションの Server アプリに関連しています。 "
次のサービスが登録されます。
Program
ファイルで次の操作を行います。Entity Framework Core と ASP.NET Core Identity:
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite( ... )); builder.Services.AddDatabaseDeveloperPageExceptionFilter(); builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();
Identity Server 上に既定の ASP.NET Core 規則を設定する AddApiAuthorization ヘルパー メソッドが追加された Identity Server:
builder.Services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
Identity Server によって生成された JWT トークンを検証するようにアプリを構成する AddIdentityServerJwt ヘルパー メソッドが追加された Authentication:
builder.Services.AddAuthentication() .AddIdentityServerJwt();
Startup.cs
のStartup.ConfigureServices
で:Entity Framework Core と ASP.NET Core Identity:
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlite( Configuration.GetConnectionString("DefaultConnection"))); services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores<ApplicationDbContext>();
警告
アプリ シークレット、接続文字列、資格情報、パスワード、個人識別番号 (PIN)、プライベート C#/.NET コード、秘密キー/トークンをクライアント側コードに格納しないでください。これは安全ではありません。 テスト/ステージング環境と運用環境では、サーバー側の Blazor コードと Web API は、プロジェクト コードまたは構成ファイル内で資格情報を維持しないように、セキュリティで保護された認証フローを使用する必要があります。 ローカル開発テスト以外では、環境変数が最も安全なアプローチではないため、環境変数を使用して機密データを格納しないようにすることをお勧めします。 ローカル開発テストでは、機密データをセキュリティで保護するために、 Secret Manager ツール をお勧めします。 詳細については、「 機密データと資格情報を安全に管理するを参照してください。
Identity Server 上に既定の ASP.NET Core 規則を設定する AddApiAuthorization ヘルパー メソッドが追加された Identity Server:
services.AddIdentityServer() .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
Identity Server によって生成された JWT トークンを検証するようにアプリを構成する AddIdentityServerJwt ヘルパー メソッドが追加された Authentication:
services.AddAuthentication() .AddIdentityServerJwt();
注意
1 つの認証スキームが登録されると、認証スキームがアプリの既定のスキームとして自動的に使用され、スキームを AddAuthentication に指定、または AuthenticationOptions 経由にする必要はありません。 詳細については、「ASP.NET Core の認証の概要」と ASP.NET Core のお知らせ (aspnet/Announcements #490) を参照してください。
Program
ファイル:
Startup.cs
のStartup.Configure
で:
Identity Server ミドルウェアによって、OpenID Connect (OIDC) のエンドポイントが公開されます。
app.UseIdentityServer();
Authentication ミドルウェアによって、要求の資格情報の検証と、要求コンテキストでのユーザーの設定が行われます。
app.UseAuthentication();
承認ミドルウェアにより、承認機能が有効になります。
app.UseAuthorization();
API 認可
"このセクションは、ソリューションの Server アプリに関連しています。 "
AddApiAuthorization ヘルパー メソッドでは、ASP.NET Core シナリオ用に Identity Server を構成します。 Identity Server は、アプリのセキュリティの問題を処理するための強力で拡張可能なフレームワークです。 Identity Server を使用すると、ほとんどの一般的なシナリオには必要のない複雑さが発生します。 そのため、使用開始時に適切であると考えられる一連の規則と構成オプションが用意されています。 認証のニーズが変わったら、Identity Server のあらゆる機能を利用し、アプリの要件に合わせて認証をカスタマイズできます。
Identity Server と共存する API の認証ハンドラーを追加する
"このセクションは、ソリューションの Server アプリに関連しています。 "
AddIdentityServerJwt ヘルパー メソッドでは、アプリに対するポリシー スキームが既定の認証ハンドラーとして構成されます。 そのポリシーは、Identity の URL 空間の /Identity
以下のサブパスにルーティングされたすべての要求を Identity で処理できるように構成されています。 それ以外のすべての要求は、JwtBearerHandler で処理されます。 さらに、このメソッドでは次のことが行われます。
- 既定のスコープ
{PROJECT NAME}API
を使用して Identity Server に API リソースを登録します。ここで、{PROJECT NAME}
プレースホルダーはアプリ作成時のプロジェクトの名前です。 - Identity Server によってアプリに対して発行されたトークンを検証するように、JWT ベアラー トークン ミドルウェアを構成します。
天気予報コントローラー
"このセクションは、ソリューションの Server アプリに関連しています。 "
WeatherForecastController
(Controllers/WeatherForecastController.cs
) では、[Authorize]
属性がクラスに適用されます。 その属性では、ユーザーはリソースにアクセスするために既定のポリシーに基づいて承認される必要があることが示されています。 既定の承認ポリシーは、AddIdentityServerJwt によって設定される既定の認証スキームを使用するように構成されています。 ヘルパー メソッドでは、アプリへの要求に対する既定のハンドラーとして JwtBearerHandler が構成されます。
アプリケーション データベース コンテキスト
"このセクションは、ソリューションの Server アプリに関連しています。 "
ApplicationDbContext
(Data/ApplicationDbContext.cs
) では、DbContext により、Identity Server 用のスキーマを含むように ApiAuthorizationDbContext<TUser> が拡張されます。 ApiAuthorizationDbContext<TUser> は、IdentityDbContext から派生しています。
データベース スキーマを完全に制御するには、使用可能な IdentityDbContext クラスの 1 つを継承し、OnModelCreating メソッドで builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value)
を呼び出すことによって、Identity スキーマを含むようにコンテキストを構成します。
OIDC 構成コントローラー
"このセクションは、ソリューションの Server アプリに関連しています。 "
OidcConfigurationController
(Controllers/OidcConfigurationController.cs
) では、OIDC パラメーターを提供するために、クライアント エンドポイントがプロビジョニングされます。
アプリの設定
"このセクションは、ソリューションの Server アプリに関連しています。 "
プロジェクト ルートにあるアプリ設定ファイル (appsettings.json
) の IdentityServer
セクションには、構成されているクライアントの一覧が記述されてます。 次の例には、1 つのクライアントがあります。 クライアント名は Client アプリのアセンブリ名に対応し、規則によって OAuth の ClientId
パラメーターにマップされます。 構成対象のアプリの種類は、プロファイルによって示されています。 プロファイルは、サーバーの構成プロセスを簡素化する規則を促進するために、内部的に使用されます。
"IdentityServer": {
"Clients": {
"{ASSEMBLY NAME}": {
"Profile": "IdentityServerSPA"
}
}
}
{ASSEMBLY NAME}
プレースホルダーは、Client アプリのアセンブリ名です (例: BlazorSample.Client
)。
認証パッケージ
"このセクションは、ソリューションの Client アプリに関連しています。 "
個人のユーザー アカウント (Individual
) を使用するようにアプリを作成すると、アプリは Microsoft.AspNetCore.Components.WebAssembly.Authentication
パッケージのパッケージ参照を自動的に受け取ります。 このパッケージには、アプリでユーザーを認証し、保護された API を呼び出すためのトークンを取得するのに役立つ一連のプリミティブが用意されています。
アプリに認証を追加する場合は、アプリに Microsoft.AspNetCore.Components.WebAssembly.Authentication
パッケージを手動で追加します。
Note
.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。
HttpClient
構成
"このセクションは、ソリューションの Client アプリに関連しています。 "
Program
ファイルでは、サーバー API への要求を行うときのアクセス トークンが含まれる HttpClient インスタンスを提供するように、名前付きの HttpClient が構成されます。 ソリューションの作成時、名前付きの HttpClient は {PROJECT NAME}.ServerAPI
になります。ここで、{PROJECT NAME}
プレースホルダーはプロジェクトの名前です。
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 が生成されます。
Note
ホストされている Blazorソリューションの一部ではない既存の Identity Server インスタンスを使用するように Blazor WebAssembly アプリを構成する場合は、HttpClient ベース アドレスの登録を IWebAssemblyHostEnvironment.BaseAddress (builder.HostEnvironment.BaseAddress
) からサーバー アプリの API 認証エンドポイント URL に変更します。
API の承認のサポート
"このセクションは、ソリューションの Client アプリに関連しています。 "
ユーザーの認証に対するサポートは、Microsoft.AspNetCore.Components.WebAssembly.Authentication
パッケージ内で提供される拡張メソッドによって、サービス コンテナーに接続されます。 このメソッドでは、アプリが既存の承認システムとやり取りするために必要なサービスが設定されます。
builder.Services.AddApiAuthorization();
アプリの構成は規則により _configuration/{client-id}
から読み込まれます。 規則により、アプリのアセンブリ名にはクライアント ID が設定されます。 オプションを指定してオーバーロードを呼び出すことにより、別のエンドポイントを指すようにこの URL を変更できます。
Imports
ファイル
"このセクションは、ソリューションの 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.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
App
コンポーネント
"このセクションは、ソリューションの 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) を参照してください。
Authentication
コンポーネント
"このセクションは、ソリューションの 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 App Service on Linux
Azure App Service on Linux にデプロイするときに、発行者を明示的に指定します。 詳しくは、「Identity を使用して SPA の Web API バックエンドをセキュリティで保護する方法」を参照してください。
API 認証での名前とロール要求
カスタム ユーザー ファクトリ
Client アプリで、カスタム ユーザー ファクトリを作成します。 Identity Server により、複数のロールが JSON 配列として 1 つの role
要求で送信されます。 1 つのロールは、要求内で文字列値として送信されます。 ファクトリにより、ユーザーのロールごとに個別の role
要求が作成されます。
CustomUserFactory.cs
:
using System.Security.Claims;
using System.Text.Json;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
public class CustomUserFactory(IAccessTokenProviderAccessor accessor)
: AccountClaimsPrincipalFactory<RemoteUserAccount>(accessor)
{
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
if (user.Identity is not null && user.Identity.IsAuthenticated)
{
var identity = (ClaimsIdentity)user.Identity;
var roleClaims = identity.FindAll(identity.RoleClaimType).ToArray();
if (roleClaims.Any())
{
foreach (var existingClaim in roleClaims)
{
identity.RemoveClaim(existingClaim);
}
var rolesElem =
account.AdditionalProperties[identity.RoleClaimType];
if (options.RoleClaim is not null && rolesElem is JsonElement roles)
{
if (roles.ValueKind == JsonValueKind.Array)
{
foreach (var role in roles.EnumerateArray())
{
var roleValue = role.GetString();
if (!string.IsNullOrEmpty(roleValue))
{
identity.AddClaim(
new Claim(options.RoleClaim, roleValue));
}
}
}
else
{
var roleValue = roles.GetString();
if (!string.IsNullOrEmpty(roleValue))
{
identity.AddClaim(
new Claim(options.RoleClaim, roleValue));
}
}
}
}
}
return user;
}
}
Client アプリでは、Program
ファイルにファクトリを登録します。
builder.Services.AddApiAuthorization()
.AddAccountClaimsPrincipalFactory<CustomUserFactory>();
Server アプリで、Identity ビルダーに AddRoles を呼び出します。これにより、ロールに関連するサービスが追加されます。
Program
ファイルでは:
using Microsoft.AspNetCore.Identity;
...
builder.Services.AddDefaultIdentity<ApplicationUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Startup.cs
:
using Microsoft.AspNetCore.Identity;
...
services.AddDefaultIdentity<ApplicationUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
Identity Server を構成する
次の方法のいずれかを使用します。
API 承認のオプション
Server アプリで:
name
要求とrole
要求を ID トークンとアクセス トークンに挿入するように、Identity Server を構成します。- JWT トークン ハンドラーでロールの既定のマッピングを禁止します。
Program
ファイルでは:
using System.IdentityModel.Tokens.Jwt;
...
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
Startup.cs
:
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
...
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
options.IdentityResources["openid"].UserClaims.Add("name");
options.ApiResources.Single().UserClaims.Add("name");
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
プロファイル サービス
Server アプリで、ProfileService
の実装を作成します。
ProfileService.cs
:
using IdentityModel;
using Duende.IdentityServer.Models;
using Duende.IdentityServer.Services;
public class ProfileService : IProfileService
{
public ProfileService()
{
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var nameClaim = context.Subject.FindAll(JwtClaimTypes.Name);
context.IssuedClaims.AddRange(nameClaim);
var roleClaims = context.Subject.FindAll(JwtClaimTypes.Role);
context.IssuedClaims.AddRange(roleClaims);
await Task.CompletedTask;
}
public async Task IsActiveAsync(IsActiveContext context)
{
await Task.CompletedTask;
}
}
Server アプリでは、Program
ファイルにプロファイル サービスを登録します。
using Duende.IdentityServer.Services;
...
builder.Services.AddTransient<IProfileService, ProfileService>();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
Server アプリで、Startup.cs
の Startup.ConfigureServices
にプロファイル サービスを登録します。
using IdentityServer4.Services;
...
services.AddTransient<IProfileService, ProfileService>();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");
承認メカニズムを使用する
Client アプリでは、この時点でコンポーネントの承認方法が機能しています。 コンポーネント内のすべての承認メカニズムで、ロールを使用してユーザーを承認できます。
AuthorizeView
コンポーネント (例:<AuthorizeView Roles="Admin">
)[Authorize]
属性ディレクティブ (AuthorizeAttribute) (例:@attribute [Authorize(Roles = "Admin")]
)手続き型ロジック (例:
if (user.IsInRole("Admin")) { ... }
)複数のロール テストがサポートされています。
if (user.IsInRole("Admin") && user.IsInRole("Developer")) { ... }
User.Identity.Name
には、 Client アプリにおいてユーザーのユーザー名が設定されます。これは通常、サインイン メール アドレスです。
UserManager
および SignInManager
サーバー アプリで次が必要な場合に、ユーザー識別子の要求の種類を設定します。
- API エンドポイントで UserManager<TUser> または SignInManager<TUser>。
- ユーザーの名前、メール アドレス、またはロックアウトの終了時刻などの IdentityUser の詳細。
.NET 6 以降の ASP.NET Core での Program.cs
の場合:
using System.Security.Claims;
...
builder.Services.Configure<IdentityOptions>(options =>
options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);
6\.0 より前の ASP.NET Core バージョンの Startup.ConfigureServices
の場合:
using System.Security.Claims;
...
services.Configure<IdentityOptions>(options =>
options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);
次の WeatherForecastController
は、Get
メソッドが呼び出されたときに UserName をログします。
Note
次の例では、C# 10 以降 (.NET 6 以降) の機能であるファイルスコープ名前空間を使用します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using BlazorSample.Server.Models;
using BlazorSample.Shared;
namespace BlazorSample.Server.Controllers;
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly UserManager<ApplicationUser> userManager;
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm",
"Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger,
UserManager<ApplicationUser> userManager)
{
this.logger = logger;
this.userManager = userManager;
}
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
var rng = new Random();
var user = await userManager.GetUserAsync(User);
if (user != null)
{
logger.LogInformation("User.Identity.Name: {UserIdentityName}", user.UserName);
}
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
前の例の場合:
Server
プロジェクトの名前空間はBlazorSample.Server
です。Shared
プロジェクトの名前空間はBlazorSample.Shared
です。
カスタム ドメインと証明書を使用した Azure App Service でのホスト
以下のガイダンスでは、次について説明します。
- Identity Server を使用してホストされている Blazor WebAssembly アプリを、カスタム ドメインを使用して Azure App Service にデプロイする方法。
- ブラウザーとの HTTPS プロトコル通信に対して、TLS 証明書を作成して使用する方法。 このガイダンスではカスタム ドメインで証明書を使用する方法に焦点を当てていますが、
contoso.azurewebsites.net
などの既定の Azure アプリのドメインを使用する場合にも同様に当てはまります。
このホスティング シナリオでは、Duende Identity Server のトークン署名キーとサイトの HTTPS セキュリティで保護されたブラウザーとの通信に同じ証明書を使用しないでください。
- この 2 つの要件に対して異なる証明書を使用することは、それぞれの目的に対して秘密キーが分離されるため、優れたセキュリティ方法です。
- ブラウザーとの通信に使用される TLS 証明書は、Identity Server のトークン署名に影響を与えることなく、個別に管理されます。
- カスタム ドメイン バインドのために Azure Key Vault で App Service アプリに証明書を提供すると、Identity Server で Azure Key Vault からトークン署名用に同じ証明書を取得することはできません。 物理パスから同じ TLS 証明書を使用するように Identity Server を構成することはできますが、セキュリティ証明書をソース管理に置くことは不適切な方法であり、ほとんどのシナリオで避ける必要があります。
次のガイダンスでは、自己署名証明書は Identity Server のトークン署名のためだけに Azure Key Vault に作成されます。 Identity Server の構成により、アプリの CurrentUser
>My
証明書ストアを介して、キー コンテナー証明書が使用されます。 カスタム ドメインで HTTPS トラフィックに使用される他の証明書は、Identity Server の署名証明書とは別に作成および構成されます。
カスタム ドメインと HTTPS を使用してホストするようにアプリ、Azure App Service、Azure Key Vault を構成するには:
プラン レベル
Basic B1
以上を使用して、App Service プランを作成します。 App Service でカスタム ドメインを使用するには、Basic B1
以上のサービス レベルが必要です。組織で管理するサイトの完全修飾ドメイン名 (FQDN) の共通名を使用して (例:
www.contoso.com
)、サイトのセキュリティで保護されたブラウザー通信 (HTTPS プロトコル) 用の PFX 証明書を作成します。 次のように証明書を作成します。- キーで使用
- デジタル署名の検証 (
digitalSignature
) - キーの暗号化 (
keyEncipherment
)
- デジタル署名の検証 (
- 強化および拡張されたキーで使用
- クライアント認証 (1.3.6.1.5.5.7.3.2)
- サーバー認証 (1.3.6.1.5.5.7.3.1)
証明書を作成するには、次のいずれかの方法、または他の適切なツールやオンライン サービスを使用します。
パスワードを記録しておきます。これは後で Azure Key Vault に証明書をインポートするために使用します。
Azure Key Vault 証明書の詳細については、Azure Key Vault のCertificate(次へ: 証明書) を選択します。
- キーで使用
新しい Azure キー コンテナーを作成するか、Azure サブスクリプションの既存のキー コンテナーを使用します。
キー コンテナーの [証明書] 領域で、PFX サイト証明書をインポートします。 後でアプリの構成に使用するので、証明書のサムプリントを記録しておきます。
Azure Key Vault で、Identity Server のトークン署名用に新しい自己署名証明書を生成します。 証明書の証明書名とサブジェクトを指定します。 サブジェクトは
CN={COMMON NAME}
と指定します。{COMMON NAME}
プレースホルダーは証明書の共通名です。 共通名には、任意の英数字を使用できます。 たとえば、CN=IdentityServerSigning
は証明書の有効なサブジェクトです。 [発行ポリシー]>[ポリシーの詳細構成] で、既定の設定を使用します。 後でアプリの構成に使用するので、証明書のサムプリントを記録しておきます。Azure portal で Azure App Service に移動し、次の構成を使用して新しいアプリ サービスを作成します。
- [発行] は、
Code
に設定します。 - [ランタイム スタック] は、アプリのランタイムに設定します。
- [SKU とサイズ] については、App Service のレベルが
Basic B1
以上であることを確認します。 App Service でカスタム ドメインを使用するには、Basic B1
以上のサービス レベルが必要です。
- [発行] は、
Azure によって App Service が作成された後、アプリの [構成] を開き、前に記録した証明書のサムプリントを指定して新しいアプリケーション設定を追加します。 アプリ設定キーは
WEBSITE_LOAD_CERTIFICATES
です。 次の例に示すように、アプリの設定値で証明書のサムプリントを区切るにはコンマを使用します。- キー:
WEBSITE_LOAD_CERTIFICATES
- 値:
57443A552A46DB...D55E28D412B943565,29F43A772CB6AF...1D04F0C67F85FB0B1
Azure portal で、アプリの設定の保存は 2 段階のプロセスです。
WEBSITE_LOAD_CERTIFICATES
のキーと値の設定を保存した後、ブレードの上部にある [保存] ボタンを選択します。- キー:
アプリの [TLS/SSL の設定] を選択します。 [秘密キー証明書 (.pfx)] を選択します。 [Key Vault 証明書のインポート] プロセスを使用します。 そのプロセスを "2 回" 使用して、HTTPS 通信用のサイトの証明書と、サイトの自己署名された Identity Server トークン署名証明書の両方をインポートします。
[カスタム ドメイン] ブレードに移動します。 ドメイン レジストラーの Web サイトで、IP アドレスとカスタム ドメイン検証 ID を使用して、ドメインを構成します。 一般的なドメイン構成には次のものが含まれます。
- ホストが
@
で、値が Azure portal の IP アドレスである A レコード。 - ホストが
asuid
で、値が Azure によって生成されて Azure portal によって提供される検証 ID である TXT レコード。
ドメイン レジストラーの Web サイトで変更を正しく保存したことを確認します。 レジストラーの Web サイトによっては、ドメイン レコードを保存するために 2 段階のプロセスが必要な場合があります。1 つ以上のレコードを個別に保存した後、別のボタンを使用してドメインの登録を更新します。
- ホストが
Azure portal の [カスタム ドメイン] ブレードに戻ります。 [カスタム ドメインの追加] を選択します。 [A レコード] オプションを選択します。 ドメインを指定し、 [検証] を選択します。 ドメイン レコードが正しく、インターネットを通して反映されている場合、ポータルで [カスタム ドメインの追加] ボタンを選択できます。
ドメイン登録の変更がインターネットのドメイン ネーム サーバー (DNS) 全体に反映されるまで、ドメイン レジストラーによって処理されてから数日かかることがあります。 ドメイン レコードが 3 営業日以内に更新されない場合は、レコードが正しく設定されていることをドメイン レジストラーで確認し、カスタマー サポートに問い合わせてください。
[カスタム ドメイン] ブレードで、ドメインの [SSL 状態] は
Not Secure
とマークされます。 [バインドの追加] リンクを選択します。 キー コンテナーからカスタム ドメイン バインド用のサイトの HTTPS 証明書を選択します。Visual Studio で、Server プロジェクトのアプリ設定ファイル (
appsettings.json
またはappsettings.Production.json
) を開きます。 Identity Server の構成で、次のKey
セクションを追加します。Name
キーに対しては、自己署名証明書のサブジェクトを指定します。 次の例の場合、キー コンテナーで割り当てられている証明書の共通名はIdentityServerSigning
であり、それによりCN=IdentityServerSigning
というサブジェクトが生成されます。"IdentityServer": { ... "Key": { "Type": "Store", "StoreName": "My", "StoreLocation": "CurrentUser", "Name": "CN=IdentityServerSigning" } },
Visual Studio で、Server プロジェクトに対する Azure App Service の "発行プロファイル" を作成します。 メニュー バーから次のように選択します。 [ビルド]>[発行]>[新規]>[Azure]>[Azure App Service] (Windows または Linux)。 Visual Studio が Azure サブスクリプションに接続されたら、 [リソースの種類] で Azure リソースの [ビュー] を設定できます。 [Web アプリ] の一覧内を移動し、アプリの App Service を見つけて選択します。 [完了] を選択します。
Visual Studio が [発行] ウィンドウに戻ると、キー コンテナーと SQL Server データベース サービスの依存関係が自動的に検出されます。
Key Vault サービスの既定の設定で構成を変更する必要はありません。
テストの目的では、Blazor テンプレートによって構成されるアプリのローカル SQLite データベースを、追加の構成を行わずにアプリでデプロイできます。 運用環境で Identity Server 用に別のデータベースを構成する方法については、この記事では説明しません。 詳細については、次のドキュメント セットのデータベース リソースを参照してください。
ウィンドウの上部にある配置プロファイル名の下にある [編集] リンクを選択します。 デプロイ先の URL を、サイトのカスタム ドメイン URL に変更します (例:
https://www.contoso.com
)。 設定を保存します。アプリの発行 Visual Studio によってブラウザー ウィンドウが開かれ、カスタム ドメインのサイトが要求されます。
Azure のドキュメントには、App Service の TLS バインドでの Azure サービスとカスタム ドメインの使用に関する詳細が含まれています。これには、A レコードの代わりに CNAME レコードを使用する方法の情報も含まれます。 詳細については、次のリソースを参照してください。
- App Service のドキュメント
- チュートリアル:既存のカスタム DNS 名を Azure App Service にマップする
- Azure App Service で TLS/SSL バインドを使用してカスタム DNS 名をセキュリティで保護する
- Azure Key Vault
Azure portal でアプリ、アプリ構成、または Azure サービスを変更した後、アプリのテストを実行するたびに、新しいプライベート モード ブラウザー ウィンドウ (Microsoft Edge InPrivate モードや Google Chrome Incognito モードなど) を使用することをお勧めします。 サイトの構成が正しい場合でも、前回のテスト実行から残っている Cookie により、サイトをテストするときに認証または承認が失敗する可能性があります。 テストを実行するたびに新しいプライベート ブラウザー ウィンドウを開くように Visual Studio を構成する方法の詳細については、「Cookie とサイト データ」セクションをご覧ください。
Azure portal で App Service の構成を変更すると、通常、更新は短時間で有効になりますが、すぐにではありません。 場合によっては、構成の変更を有効にするために App Service が再起動されるまでしばらく待つ必要があります。
Identity Server キー署名証明書の読み込みに関する問題のトラブルシューティングを行う場合は、Azure portal の Kudu PowerShell コマンド シェルで次のコマンドを実行します。 このコマンドにより、アプリで CurrentUser
>My
証明書ストアからアクセスできる証明書の一覧が提供されます。 出力には、アプリをデバッグするときに役立つ証明書のサブジェクトとサムプリントが含まれています。
Get-ChildItem -path Cert:\CurrentUser\My -Recurse | Format-List DnsNameList, Subject, Thumbprint, EnhancedKeyUsageList
トラブルシューティング
ログ機能
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]
その他の技術情報
- Azure App Service にデプロイする
- Key Vault から証明書をインポートする (Azure ドキュメント)
- ASP.NET Core Blazor WebAssembly のセキュリティに関するその他のシナリオ
- セキュリティで保護された既定のクライアントを使用する、アプリ内の認証または承認されていない Web API 要求
- プロキシ サーバーとロード バランサーを使用するために ASP.NET Core を構成する: 次のガイダンスが含まれます。
- 転送されたヘッダー ミドルウェアを使用した、プロキシ サーバーと内部ネットワークの間での HTTPS スキーム情報の保持。
- 追加のシナリオとユース ケース (手動スキーム構成を含む)、正しい要求ルーティングのための要求パスの変更、Linux および IIS 以外のリバース プロキシのための要求スキームの転送。
- Duende Identity Server
ASP.NET Core