次の方法で共有


ASP.NET Core のサーバー側の Blazor アプリを保護する

Note

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

警告

このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、「.NET および .NET Core サポート ポリシー」を参照してください。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

この記事では、サーバー側の Blazor アプリを ASP.NET Core アプリケーションとしてセキュリティで保護する方法について説明します。

サーバー側の Blazor アプリは、セキュリティについて ASP.NET Core アプリと同じ方法で構成されています。 詳細については、「ASP.NET Core Security の概要」を参照してください。

認証コンテキストはアプリの起動時、つまりアプリが WebSocket 最初に接続するときにのみ確立されます。 認証コンテキストは、回線の有効期間を通して維持されます。 アプリは、ユーザーの認証状態を定期的 (30 分ごと) に再検証します。

アプリでカスタム サービス用にユーザーをキャプチャしたり、ユーザーに対する更新に対応したりする必要がある場合は、「サーバー側の ASP.NET Core Blazor の追加のセキュリティ シナリオ」をご覧ください。

Blazor は、すべてのページ ナビゲーションで Cookie を使って新しい HTTP 要求を行う従来のサーバーでレンダリングされる Web アプリとは異なるものです。 ナビゲーション イベントの間に認証がチェックされます。 ただし、Cookie は関係しません。 Cookie は、サーバーに対して HTTP 要求を行うときにのみ送信され、ユーザーが Blazor アプリ内を移動したときには行われません。 ナビゲーション中に、ユーザーの認証状態が Blazor 回線内でチェックされます。この回線は、再検証 AuthenticationStateProvider](#additional-authentication-state-providers) を使用してサーバー上でいつでも更新できます。

重要

カスタム NavigationManager を実装してナビゲーションの間に認証の検証を行うことは推奨されません。 ナビゲーションの間にアプリでカスタム認証状態ロジックを実行する必要がある場合は、カスタム AuthenticationStateProvider を使います。

Note

この記事のコード例では、null 許容参照型 (NRT) と .NET コンパイラの null 状態スタティック分析を採用しています。これは、.NET 6 以降の ASP.NET Core でサポートされています。 ASP.NET Core 5.0 以前をターゲットとする場合は、この記事の例から null 型の指定 (?) を削除してください。

機密データと資格情報のサーバー側セキュリティ

テスト/ステージング環境と運用環境では、サーバー側の Blazor コードと Web API は、プロジェクト コードまたは構成ファイル内で資格情報を維持しないように、セキュリティで保護された認証フローを使用する必要があります。 ローカル開発テスト以外では、環境変数が最も安全なアプローチではないため、環境変数を使用して機密データを格納しないようにすることをお勧めします。 ローカル開発テストでは、機密データをセキュリティで保護するために、 Secret Manager ツール をお勧めします。 詳細については、次のリソースを参照してください。

クライアント側およびサーバー側のローカル開発とテストの場合は、 Secret Manager ツール を使用して機密性の高い資格情報をセキュリティで保護します。

プロジェクト テンプレート

ASP.NET Core Blazor 用のツール」のガイダンスに従って、新しいサーバー側の Blazor アプリを作成します。

サーバー側のアプリ テンプレートを選択し、プロジェクトを構成したら、[認証の種類] でアプリの認証を選択します。

  • なし (既定値): 認証なし。
  • [個別のアカウント]: ユーザー アカウントは、ASP.NET Core Identity を使用してアプリ内に格納されます。
  • なし (既定値): 認証なし。
  • [個別のアカウント]: ユーザー アカウントは、ASP.NET Core Identity を使用してアプリ内に格納されます。
  • Microsoft identity プラットフォーム: 詳細については、「ASP.NET Core Blazor の認証と認可」をご覧ください。
  • [Windows]: Windows 認証を使用します。

BlazorIdentity UI (個人アカウント)

Blazor では、[個人アカウント] の認証オプションを選んだ場合の、完全な Blazor ベースの Identity UI の生成がサポートされます。

Blazor Web App テンプレートで SQL Server データベースの Identity コードがスキャフォールディングされます。 コマンド ライン バージョンでは、SQLite が使用され、Identity の SQLite データベースが含まれています。

テンプレート:

  • 認証されたユーザーでの対話型サーバー側レンダリング (対話型 SSR) とクライアント側レンダリング (CSR) のシナリオがサポートされています。
  • IdentityRazor コンポーネントと、ユーザーのサインインとサインアウトなどの日常的な認証タスクに関連するロジックを追加します。また、Identity コンポーネントでは、サードパーティ製アプリを使用したアカウントの確認やパスワードの回復多要素認証などの高度な Identity 機能もサポートされています。 なお、Identity コンポーネント自体は対話機能をサポートしていません。
  • Identity 関連のパッケージと依存関係を追加する。
  • _Imports.razor の Identity パッケージを参照する。
  • カスタム ユーザー Identity クラス (ApplicationUser) を作成します。
  • EF Core データベース コンテキスト (ApplicationDbContext) を作成して登録します。
  • 組み込み Identity エンドポイントのルーティングを構成します。
  • Identity 検証とビジネス ロジックを含める。

Blazor フレームワークの Identity コンポーネントを調べるには、Blazor Web App プロジェクト テンプレート内の Account フォルダー (参照ソース)Pages および Shared フォルダー内でそれらにアクセスします。

対話型 WebAssembly または対話型自動レンダリング モードを選択すると、サーバーはすべての認証要求と認可要求を処理し、Identity コンポーネントは Blazor Web App のメイン プロジェクト内のサーバー上で静的にレンダリングします。

このフレームワークは、ユーザーの認証状態をブラウザーにフローするためのカスタム AuthenticationStateProvider をサーバー プロジェクトとクライアント (.Client) プロジェクトの両方で提供します。 サーバー プロジェクトは AddAuthenticationStateSerialization を呼び出し、クライアント プロジェクトは AddAuthenticationStateDeserialization を呼び出します。 クライアントではなくサーバーで認証を行う場合、アプリは、プリレンダリング中、.NET WebAssembly ランタイムが初期化される前に認証状態にアクセスできます。 カスタムの AuthenticationStateProvider の実装は、Persistent Component State サービス (PersistentComponentState) を使用して認証状態を HTML コメントにシリアル化し、その後に WebAssembly からそれを再度読み取って新しい AuthenticationState インスタンスを作成します。 詳細については、「Blazor Web App での認証状態の管理」セクションをご覧ください。

対話型サーバー ソリューションの場合にのみ、IdentityRevalidatingAuthenticationStateProvider (参照ソース) は、対話型回線が接続されてから 30 分ごとに接続されたユーザーのセキュリティ スタンプを再検証するサーバー側 AuthenticationStateProvider となります。

対話型 WebAssembly または対話型自動レンダリング モードを選択すると、サーバーはすべての認証要求と認可要求を処理し、Identity コンポーネントは Blazor Web App のメイン プロジェクト内のサーバー上で静的にレンダリングします。 プロジェクト テンプレートには、.Client プロジェクトに PersistentAuthenticationStateProvider クラス (参照ソース) が含まれており、サーバーとブラウザーの間でユーザーの認証状態を同期します。 このクラスは、AuthenticationStateProvider のカスタム実装です。 このプロバイダーは、Persistent Component State サービス (PersistentComponentState) を使用して認証状態をプリレンダリングし、それをページに保持します。

Blazor Web App のメイン プロジェクトでは、認証状態プロバイダーの名前は IdentityRevalidatingAuthenticationStateProvider (参照ソース) (サーバーのインタラクティビティ ソリューションのみ) または PersistingRevalidatingAuthenticationStateProvider (参照ソース) (WebAssembly または自動インタラクティビティ ソリューション) です。

BlazorIdentity は、ファクトリで作成されていない DbContext インスタンスに依存します。これは、プロジェクト テンプレートの Identity コンポーネントが対話機能をサポートせずに静的にレンダリングするには DbContext で十分であるため、意図的なものです。

Identity コンポーネントに対して同時に静的 SSR を適用しているときに、グローバル インタラクティブレンダリング モードがどのように非 Identity コンポーネントに適用されるかについては、「ASP.NET Core の Blazor レンダリング モード」を参照してください。

プリレンダリングされた状態の永続化の詳細については、「ASP.NET Core Razor コンポーネントのプリレンダリング」を参照してください。

Blazor Identity UI の詳細と、ソーシャル Web サイトを介した外部ログインの統合に関するガイダンスについては、「.NET 8 の identity の新機能」をご覧ください。

Note

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

Blazor Web App で認証状態を管理する

このセクションは、以下を採用する Blazor Web App に適用されます。

  • 個人アカウント
  • クライアント側レンダリング (CSR、WebAssembly ベースの対話性)。

クライアント側認証状態プロバイダーは、Blazor でのみ使用され、ASP.NET Core 認証システムと統合されません。 プリレンダリング中、Blazor によりページで定義されたメタデータが考慮され、ASP.NET Core 認証システムを使用して、ユーザーが認証されているかどうかが判断されます。 ユーザーが 1 つのページから別のページに移動すると、クライアント側の認証プロバイダーが使用されます。 ユーザーがページを更新すると (ページ全体の再読み込み)、クライアント側の認証状態プロバイダーはサーバーでの認証の決定に関与しません。 ユーザーの状態はサーバーによって保持されないため、クライアント側で維持されていた認証状態は失われます。

これに対処するには、ASP.NET Core 認証システム内で認証を実行するのが最適な方法です。 クライアント側の認証状態プロバイダーでは、ユーザーの認証状態の反映のみが処理されます。 認証状態プロバイダーでこれを実現する方法の例は、Blazor Web App プロジェクト テンプレートによって以下に示されています。

以下のように、サーバー プロジェクトの Program ファイル内で AddAuthenticationStateSerialization を呼び出します。これによって Persistent Component State サービス (PersistentComponentState) を使用してサーバー側 AuthenticationStateProvider によって返された AuthenticationState がシリアル化されます。

builder.Services.AddRazorComponents()
    .AddInteractiveWebAssemblyComponents()
    .AddAuthenticationStateSerialization();

この API がシリアル化するのは、ブラウザーでアクセスするためのサーバー側の名前とロールの要求だけです。 すべての要求を含めるには、以下のように、サーバー側の AddAuthenticationStateSerialization の呼び出しで SerializeAllClaimstrue に設定します。

builder.Services.AddRazorComponents()
    .AddInteractiveWebAssemblyComponents()
    .AddAuthenticationStateSerialization(
        options => options.SerializeAllClaims = true);

クライアント (.Client) プロジェクトの Program ファイル内で、AddAuthenticationStateDeserialization を呼び出します。これによって AuthenticationStateData および Persistent Component State サービス (PersistentComponentState) を使用してサーバーから逆シリアル化された AuthenticationState の状態で AuthenticationStateProvider が追加されます。 サーバー プロジェクトには、対応する AddAuthenticationStateSerialization の呼び出しが必要です。

builder.Services.AddAuthorizationCore();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddAuthenticationStateDeserialization();

Note

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

スキャフォールディング Identity

サーバー側の Blazor アプリへの Identity のスキャフォールディングについて詳しくは、「ASP.NET Core プロジェクトでの Identity のスキャフォールディング」をご覧ください。

サーバー側の Blazor アプリに Identity をスキャフォールディングします。

外部プロバイダーからの追加のクレームとトークン

外部プロバイダーからの追加の要求を格納するには、「ASP.NET Core で外部プロバイダーからの追加の要求とトークンを保持する」を参照してください。

Identity Server を使用した Azure App Service on Linux

Identity Server を使用して Azure App Service on Linux にデプロイするときに、発行者を明示的に指定します。 詳しくは、「Identity を使用して SPA の Web API バックエンドをセキュリティで保護する方法」を参照してください。

コンポーネントにスコープ設定されたサービス用の AuthenticationStateProvider を挿入する

正しく初期化されていない AuthenticationStateProvider の新しいインスタンスが作成されるため、カスタム スコープ内で AuthenticationStateProvider の解決を試みないでください。

コンポーネントにスコープ設定されたサービス内の AuthenticationStateProvider にアクセスするには、@inject ディレクティブまたは [Inject]属性を使用して AuthenticationStateProvider を挿入し、それをパラメーターとしてサービスに渡します。 この方法により、AuthenticationStateProvider の正しい初期化されたインスタンスが各ユーザー アプリ インスタンスに確実に使われます。

ExampleService.cs:

public class ExampleService
{
    public async Task<string> ExampleMethod(AuthenticationStateProvider authStateProvider)
    {
        var authState = await authStateProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        if (user.Identity is not null && user.Identity.IsAuthenticated)
        {
            return $"{user.Identity.Name} is authenticated.";
        }
        else
        {
            return "The user is NOT authenticated.";
        }
    }
}

サービスをスコープとして登録します。 サーバー側の Blazor アプリでは、スコープが設定されたサービスの有効期間は、クライアント接続回線の期間と同じです。

Program ファイル:

builder.Services.AddScoped<ExampleService>();

Startup.csStartup.ConfigureServices で:

services.AddScoped<ExampleService>();

次の InjectAuthStateProvider コンポーネントでは、以下のことを行います。

InjectAuthStateProvider.razor:

@page "/inject-auth-state-provider"
@inherits OwningComponentBase
@inject AuthenticationStateProvider AuthenticationStateProvider

<h1>Inject <code>AuthenticationStateProvider</code> Example</h1>

<p>@message</p>

@code {
    private string? message;
    private ExampleService? ExampleService { get; set; }

    protected override async Task OnInitializedAsync()
    {
        ExampleService = ScopedServices.GetRequiredService<ExampleService>();

        message = await ExampleService.ExampleMethod(AuthenticationStateProvider);
    }
}
@page "/inject-auth-state-provider"
@inject AuthenticationStateProvider AuthenticationStateProvider
@inherits OwningComponentBase

<h1>Inject <code>AuthenticationStateProvider</code> Example</h1>

<p>@message</p>

@code {
    private string? message;
    private ExampleService? ExampleService { get; set; }

    protected override async Task OnInitializedAsync()
    {
        ExampleService = ScopedServices.GetRequiredService<ExampleService>();

        message = await ExampleService.ExampleMethod(AuthenticationStateProvider);
    }
}

詳しくは、「ASP.NET Core Blazor 依存関係の挿入」で OwningComponentBase についてのガイダンスをご覧ください。

カスタム AuthenticationStateProvider を使用したプリレンダリング中に未承認のコンテンツが表示される

カスタムの AuthenticationStateProvider を使ってプリレンダリング中に、認可されていないコンテンツ (たとえば、AuthorizeView コンポーネント内のコンテンツ) が表示されないようにするには、次のいずれかの方法を採用します。

  • プリレンダリングを無効にする: ルート コンポーネントではないアプリのコンポーネント階層の最上位コンポーネントで、prerender パラメーターを false に設定してレンダリング モードを指定します。

    Note

    ルート コンポーネントを対話型にすること (App コンポーネントなど) はサポートされていません。 そのため、プリレンダリングを App コンポーネントで直接無効にすることはできません。

    Blazor Web App プロジェクト テンプレートに基づくアプリの場合、プリレンダリングの無効化は通常、App コンポーネント内で Routes コンポーネントが使用されている場所 (Components/App.razor) で行います。

    <Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />
    

    また、HeadOutlet コンポーネントのプリレンダリングを無効にします。

    <HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />
    

    Routes コンポーネント インスタンスに適用されるレンダリング モードを選択的に制御することもできます。 たとえば、「ASP.NET Core Blazor レンダリング モード」を参照してください。

  • プリレンダリングを無効にする。_Host.cshtml ファイルを開き、コンポーネント タグ ヘルパーrender-mode 属性を、Server に変更します。

    <component type="typeof(App)" render-mode="Server" />
    
  • アプリが起動する前にサーバーでユーザーを認証する。このアプローチを採用するには、アプリが Identity ベースのサインイン ページを使用してユーザーの初期要求に応答するか、Blazor エンドポイントへの要求を監視して、認証されるまで防ぐ必要があります。 詳細については、「認可によって保護されたユーザー データを使って ASP.NET Core アプリを作成する」を参照してください。 認証後は、プリレンダリングされた Razor コンポーネント内の未承認のコンテンツは、ユーザーがコンテンツを表示することが本当に承認されたときにのみ表示されます。

ユーザー状態の管理

名前には "state" という単語が含まれますが、AuthenticationStateProvider は "一般的なユーザーの状態" を格納するためのものではありません。 AuthenticationStateProvider は、ユーザーの認証状態 (アプリにサインインしているかどうか、サインインに使われているユーザー) をアプリに示すだけです。

認証は、Razor Pages および MVC アプリと同じ ASP.NET Core Identity 認証を使用します。 ASP.NET Core Identity に格納されたユーザー状態は、アプリにコードを追加しなくても Blazor に流れます。 アプリの Blazor 部分で Identity の機能を有効にするには、ASP.NET Core Identity の記事とチュートリアルのガイダンスに従ってください。

ASP.NET Core Identity の外部での一般的な状態管理のガイダンスについては、「ASP.NET Core Blazor 状態管理」をご覧ください。

追加の認証状態プロバイダー

AuthenticationStateProviderから派生した 2 つの追加クラスは、サーバーでの認証状態の管理に役立ちます。

Note

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

サインアウト時の認証状態管理

サーバー側の Blazor は、すべてのブラウザー タブを含め、回線の有効期間中、ユーザーの認証状態を保持します。 ユーザーが 1 つのタブでサインアウトしたときにすべての [ブラウザー] タブでユーザーをプロアクティブにサインオフするには、短い RevalidationIntervalRevalidatingServerAuthenticationStateProvider (参照ソース) を実装する必要があります。

Note

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。

一時的なリダイレクト URL の有効期間

このセクションは Blazor Web App に適用されます。

RazorComponentsServiceOptions.TemporaryRedirectionUrlValidityDuration オプションを使用して取得するか、Blazor サーバー側のレンダリングによって出力される一時的なリダイレクト URL に対して ASP.NET Core データ保護の有効期間を設定します。 これらは一時的にしか使用されないため、その有効期間は、クライアントで URL を受信し、ナビゲーションを開始するために必要な長さであれば十分です。 ただし、サーバー間のクロック スキューを許可するために十分な長さも必要です。 既定値は 5 分です。

次の例では、値は 7 分に延長されています。

builder.Services.AddRazorComponents(options => 
    options.TemporaryRedirectionUrlValidityDuration = 
        TimeSpan.FromMinutes(7));

その他のリソース