ASP.NET Core Blazorの認証状態

Note

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

警告

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

重要

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

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

この記事では、カスタム 認証状態プロバイダーを作成し、ユーザー認証状態変更通知をコードで受信する方法について説明します。

サーバー側およびクライアント側の Blazor アプリに対して行われる一般的なアプローチは似ていますが、正確な実装が異なるため、この記事では、サーバー側の Blazor アプリとクライアント側の Blazor アプリの間でピボットします。 記事の上部にあるピボット セレクターを使用して、作業中の Blazor プロジェクトの種類に合わせて記事のピボットを変更します。

  • サーバー側 Blazor アプリ (Server ピボット): .NET 7 以前の Blazor Server と、.NET 8 以降の Blazor Web App のサーバー プロジェクト。
  • クライアント側 Blazor アプリ (Blazor WebAssembly ピボット): .NETのすべてのバージョンのBlazor WebAssembly、または .NET 8 以降のBlazor Web Appの.Client プロジェクト。

抽象 AuthenticationStateProvider クラス

Blazor フレームワークには、次のメンバーを持つ現在のユーザーの認証状態に関する情報を提供する抽象 AuthenticationStateProvider クラスが含まれています。

  • GetAuthenticationStateAsync: 現在のユーザーの認証状態を非同期的に取得します。
  • AuthenticationStateChanged: 認証状態が変更されたときに通知を提供するイベント。 たとえば、ユーザーがアプリにサインインまたはサインアウトすると、このイベントが発生する可能性があります。
  • NotifyAuthenticationStateChanged: 認証状態変更イベントを発生させます。

カスタムの AuthenticationStateProvider を実装する

アプリは、Blazor アプリの認証と承認のサポートを提供するMicrosoft.AspNetCore.Components.Authorization NuGet パッケージを参照する必要があります。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

Program ファイルで、次の認証、承認、およびカスケード認証状態サービスを構成します。

認証が有効になっている Blazor プロジェクト テンプレートのいずれかから Blazor アプリを作成すると、そのアプリは次のサービス登録で事前構成されます。これには、カスケード パラメーターとして認証状態が公開されます。 詳しくは、「ASP.NET Core Blazor の認証と承認」と、その記事の「Router コンポーネントを使用して未承認のコンテンツをカスタマイズする」セクションの追加情報をご覧ください。

using Microsoft.AspNetCore.Components.Authorization;

...

builder.Services.AddAuthorization();
builder.Services.AddCascadingAuthenticationState();

Program ファイルで、認証サービスと承認サービスを構成します。

認証が有効にされた Blazor プロジェクト テンプレートのいずれかから Blazor アプリを作成すると、そのアプリには次のサービス登録が含まれます。

using Microsoft.AspNetCore.Components.Authorization;

...

builder.Services.AddAuthorization();

Startup.csStartup.ConfigureServices で認証サービスと承認サービスを構成します。

認証が有効にされた Blazor プロジェクト テンプレートのいずれかから Blazor アプリを作成すると、そのアプリには次のサービス登録が含まれます。

using Microsoft.AspNetCore.Components.Authorization;

...

services.AddAuthorization();

Blazor WebAssembly アプリ (すべての .NET バージョン) または Blazor Web App (.NET 8 以降) の .Client プロジェクトでは、Program ファイルで認証サービス、承認サービス、およびカスケード認証状態サービスを構成します。

認証が有効になっている Blazor プロジェクト テンプレートのいずれかから Blazor アプリを作成すると、そのアプリは次のサービス登録で事前構成されます。これには、カスケード パラメーターとして認証状態が公開されます。 詳しくは、「ASP.NET Core Blazor の認証と承認」と、その記事の「Router コンポーネントを使用して未承認のコンテンツをカスタマイズする」セクションの追加情報をご覧ください。

using Microsoft.AspNetCore.Components.Authorization;

...

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

Program ファイルで、認証サービスと承認サービスを構成します。

認証が有効にされた Blazor プロジェクト テンプレートのいずれかから Blazor アプリを作成すると、そのアプリには次のサービス登録が含まれます。

using Microsoft.AspNetCore.Components.Authorization;

...

builder.Services.AddAuthorizationCore();

AuthenticationStateProvider をサブクラス化し、GetAuthenticationStateAsync をオーバーライドして、ユーザーの認証状態を作成します。 前の例では、すべてのユーザーがユーザー名 mrfibuli で認証されます。

CustomAuthStateProvider.cs:

using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;

public class CustomAuthStateProvider : AuthenticationStateProvider
{
    public override Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var identity = new ClaimsIdentity(
        [
            new Claim(ClaimTypes.Name, "mrfibuli"),
        ], "Custom Authentication");

        var user = new ClaimsPrincipal(identity);

        return Task.FromResult(new AuthenticationState(user));
    }
}

Note

新しい ClaimsIdentity を作成する上記のコードでは、C# 12 (.NET 8) で導入された簡略化されたコレクション初期化を使用します。 詳細については、「コレクション式 - C# 言語リファレンス」をご覧ください。

CustomAuthStateProvider サービスは Program ファイルに登録されます。 AddScopedスコープ付きサービスを登録します。

builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();

Blazor Server アプリで、スコープ付きサービスを、AddServerSideBlazorへの呼び出しAddScoped で登録します。

builder.Services.AddServerSideBlazor();

builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();

Blazor Server アプリで、スコープ付きサービスを、AddServerSideBlazorへの呼び出しAddScoped で登録します。

services.AddServerSideBlazor();

services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();

CustomAuthStateProvider サービスは Program ファイルに登録されます。 シングルトンサービスを AddSingleton で登録します。

builder.Services.AddSingleton<AuthenticationStateProvider, CustomAuthStateProvider>();

存在しない場合は、@using ステートメントを _Imports.razor ファイルに追加して、コンポーネント間で Microsoft.AspNetCore.Components.Authorization 名前空間を使用できるようにします。

@using Microsoft.AspNetCore.Components.Authorization;

Router コンポーネント定義で、ルート ビュー コンポーネントを確認するか、AuthorizeRouteView に変更します。 Router コンポーネントの場所は、アプリの種類によって異なります。 プロジェクト内でコンポーネントの場所がわからない場合は、そのコンポーネントの場所を検索します。

<Router ...>
    <Found ...>
        <AuthorizeRouteView RouteData="routeData" 
            DefaultLayout="typeof(Layout.MainLayout)" />
        ...
    </Found>
</Router>

Note

認証が有効にされた Blazor プロジェクト テンプレートのいずれかから Blazor アプリを作成すると、そのアプリには AuthorizeRouteView コンポーネントが含まれます。 詳しくは、「ASP.NET Core Blazor の認証と承認」と、その記事の「Router コンポーネントを使用して未承認のコンテンツをカスタマイズする」セクションの追加情報をご覧ください。

Router コンポーネントが配置されている場所:

  • ルート ビュー コンポーネントを確認するか、AuthorizeRouteView に変更します。
  • CascadingAuthenticationState コンポーネントを確認するか、Router コンポーネントの周囲にそのコンポーネントを追加します。

Router コンポーネントの場所は、アプリの種類によって異なります。 プロジェクト内でコンポーネントの場所がわからない場合は、そのコンポーネントの場所を検索します。

<CascadingAuthenticationState>
    <Router ...>
        <Found ...>
            <AuthorizeRouteView RouteData="routeData" 
                DefaultLayout="typeof(MainLayout)" />
            ...
        </Found>
    </Router>
</CascadingAuthenticationState>

Note

認証が有効にされた Blazor プロジェクト テンプレートのいずれかから Blazor アプリを作成すると、そのアプリには AuthorizeRouteView コンポーネントと CascadingAuthenticationState コンポーネントが含まれます。 詳しくは、「ASP.NET Core Blazor の認証と承認」と、その記事の「Router コンポーネントを使用して未承認のコンテンツをカスタマイズする」セクションの追加情報をご覧ください。

次の AuthorizeView コンポーネント例は、認証されたユーザー名を示しています。

<AuthorizeView>
    <Authorized>
        <p>Hello, @context.User.Identity?.Name!</p>
    </Authorized>
    <NotAuthorized>
        <p>You're not authorized.</p>
    </NotAuthorized>
</AuthorizeView>

AuthorizeView の使用に関するガイダンスについては、「ASP.NET Core Blazor の認証と承認」をご覧ください。

認証状態変更通知

カスタム AuthenticationStateProvider では、AuthenticationStateProvider 基本クラスで NotifyAuthenticationStateChanged を呼び出して、認証状態の変更を再レンダリングするようコンシューマーに通知できます。

次の例は、この記事で前述されている「カスタムの AuthenticationStateProvider を実装する」セクションのガイダンスに従って行ったカスタム AuthenticationStateProvider の実装に基づいています。 そのセクションのガイダンスに既に従っている場合は、次の CustomAuthStateProvider はセクションに示されているガイダンスに取って代わります。

次の CustomAuthStateProvider の実装では、ユーザーをサインインさせて、認証状態の変更をコンシューマーに通知するために、カスタム メソッド AuthenticateUser を公開してします。

CustomAuthStateProvider.cs:

using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;

public class CustomAuthStateProvider : AuthenticationStateProvider
{
    public override Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var identity = new ClaimsIdentity();
        var user = new ClaimsPrincipal(identity);

        return Task.FromResult(new AuthenticationState(user));
    }

    public void AuthenticateUser(string userIdentifier)
    {
        var identity = new ClaimsIdentity(
        [
            new Claim(ClaimTypes.Name, userIdentifier),
        ], "Custom Authentication");

        var user = new ClaimsPrincipal(identity);

        NotifyAuthenticationStateChanged(
            Task.FromResult(new AuthenticationState(user)));
    }
}

Note

新しい ClaimsIdentity を作成する上記のコードでは、C# 12 (.NET 8) で導入された簡略化されたコレクション初期化を使用します。 詳細については、「コレクション式 - C# 言語リファレンス」をご覧ください。

コンポーネントでは:

  • AuthenticationStateProvider を挿入する。
  • ユーザーの識別子を保持するフィールドを追加します。
  • ボタンと、AuthenticationStateProviderCustomAuthStateProvider にキャストしてからユーザーの識別子を使って AuthenticateUser を呼び出すメソッドを追加します。
@inject AuthenticationStateProvider AuthenticationStateProvider

<input @bind="userIdentifier" />
<button @onclick="SignIn">Sign in</button>

<AuthorizeView>
    <Authorized>
        <p>Hello, @context.User.Identity?.Name!</p>
    </Authorized>
    <NotAuthorized>
        <p>You're not authorized.</p>
    </NotAuthorized>
</AuthorizeView>

@code {
    public string userIdentifier = string.Empty;

    private void SignIn()
    {
        ((CustomAuthStateProvider)AuthenticationStateProvider)
            .AuthenticateUser(userIdentifier);
    }
}

上記のアプローチを拡張し、カスタム サービスを使って認証状態の変更の通知をトリガーできます。 次の CustomAuthenticationService クラスは、認証状態プロバイダーがサブスクライブできるイベント (UserChanged) で、現在のユーザーの要求プリンシパルをバッキング フィールド (currentUser) に保持します。このイベントは NotifyAuthenticationStateChanged を呼び出します。 このセクションで後ほど示す追加の構成では、CurrentUser を設定して UserChanged イベントをトリガーするロジックと共に、CustomAuthenticationService をコンポーネントに挿入できます。

CustomAuthenticationService.cs:

using System.Security.Claims;

public class CustomAuthenticationService
{
    public event Action<ClaimsPrincipal>? UserChanged;
    private ClaimsPrincipal? currentUser;

    public ClaimsPrincipal CurrentUser
    {
        get { return currentUser ?? new(); }
        set
        {
            currentUser = value;

            if (UserChanged is not null)
            {
                UserChanged(currentUser);
            }
        }
    }
}

Program ファイルで、CustomAuthenticationService を依存関係挿入コンテナーに登録します。

builder.Services.AddScoped<CustomAuthenticationService>();

Startup.csStartup.ConfigureServices で、CustomAuthenticationService を依存関係挿入コンテナーに登録します。

services.AddScoped<CustomAuthenticationService>();

Program ファイルで、CustomAuthenticationService を依存関係挿入コンテナーに登録します。

builder.Services.AddSingleton<CustomAuthenticationService>();

次の CustomAuthStateProvider は、CustomAuthenticationService.UserChanged イベントをサブスクライブします。 GetAuthenticationStateAsync メソッドは、ユーザーの認証状態を返します。 初期状態で認証状態は CustomAuthenticationService.CurrentUserの値に基づいています。 ユーザーに変更があると、GetAuthenticationStateAsync への呼び出しに対して、新しいユーザー (new AuthenticationState(newUser)) に新しい認証状態が作成されます。

using Microsoft.AspNetCore.Components.Authorization;

public class CustomAuthStateProvider : AuthenticationStateProvider
{
    private AuthenticationState authenticationState;

    public CustomAuthStateProvider(CustomAuthenticationService service)
    {
        authenticationState = new AuthenticationState(service.CurrentUser);

        service.UserChanged += (newUser) =>
        {
            authenticationState = new AuthenticationState(newUser);
            NotifyAuthenticationStateChanged(Task.FromResult(authenticationState));
        };
    }

    public override Task<AuthenticationState> GetAuthenticationStateAsync() =>
        Task.FromResult(authenticationState);
}

次のコンポーネントの SignIn メソッドでは、CustomAuthenticationService.CurrentUser に設定するために、ユーザーの識別子の要求プリンシパルが作成されます。

@using System.Security.Claims
@inject CustomAuthenticationService AuthService

<input @bind="userIdentifier" />
<button @onclick="SignIn">Sign in</button>

<AuthorizeView>
    <Authorized>
        <p>Hello, @context.User.Identity?.Name!</p>
    </Authorized>
    <NotAuthorized>
        <p>You're not authorized.</p>
    </NotAuthorized>
</AuthorizeView>

@code {
    public string userIdentifier = string.Empty;

    private void SignIn()
    {
        var currentUser = AuthService.CurrentUser;

        var identity = new ClaimsIdentity(
            [
                new Claim(ClaimTypes.Name, userIdentifier),
            ],
            "Custom Authentication");

        var newUser = new ClaimsPrincipal(identity);

        AuthService.CurrentUser = newUser;
    }
}

Note

新しい ClaimsIdentity を作成する上記のコードでは、C# 12 (.NET 8) で導入された簡略化されたコレクション初期化を使用します。 詳細については、「コレクション式 - C# 言語リファレンス」をご覧ください。

その他のリソース