次の方法で共有


ASP.NET Core Blazorの認証状態

Note

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

警告

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

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

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

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

抽象 AuthenticationStateProvider クラス

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

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

カスタムの AuthenticationStateProvider を実装する

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

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.ConfigureServicesStartup.cs で認証サービスと承認サービスを構成します。

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

using Microsoft.AspNetCore.Components.Authorization;

...

services.AddAuthorization();

Blazor WebAssembly アプリ (すべての .NET バージョン) または .Client (.NET 8 以降) の Blazor Web App プロジェクトでは、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 アプリで、スコープ付きサービスを、AddScopedへの呼び出しAddServerSideBlazor で登録します。

builder.Services.AddServerSideBlazor();

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

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

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;

AuthorizeRouteView コンポーネント定義で、ルート ビュー コンポーネントを確認するか、Router に変更します。 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 では、NotifyAuthenticationStateChanged 基本クラスで AuthenticationStateProvider を呼び出して、認証状態の変更を再レンダリングするようコンシューマーに通知できます。

次の例は、この記事で前述されている「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 クラスは、認証状態プロバイダーがサブスクライブできるイベント (currentUser) で、現在のユーザーの要求プリンシパルをバッキング フィールド (UserChanged) に保持します。このイベントは NotifyAuthenticationStateChanged を呼び出します。 このセクションで後ほど示す追加の構成では、CustomAuthenticationService を設定して CurrentUser イベントをトリガーするロジックと共に、UserChanged をコンポーネントに挿入できます。

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.ConfigureServicesStartup.cs で、CustomAuthenticationService を依存関係挿入コンテナーに登録します。

services.AddScoped<CustomAuthenticationService>();

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

builder.Services.AddSingleton<CustomAuthenticationService>();

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

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# 言語リファレンス」をご覧ください。

その他のリソース