ASP.NET Core Blazor 身份验证状态

注意

此版本不是本文的最新版本。 有关当前版本,请参阅本文.NET 9 版本。

警告

此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 有关当前版本,请参阅本文.NET 9 版本。

重要

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

有关当前版本,请参阅本文.NET 9 版本。

本文介绍如何创建自定义身份验证状态提供程序并在代码中接收用户身份验证状态更改通知。

服务器端和客户端 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 类,用于提供有关当前用户的身份验证状态的信息,其中包含以下成员:

实现自定义 AuthenticationStateProvider

应用必须引用 Microsoft.AspNetCore.Components.Authorization NuGet 包,该包为 Blazor 应用提供身份验证和授权支持。

注意

有关将包添加到 .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 版本)或 .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));
    }
}

注意

上述创建了新 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>();

如果不存在,请向 _Imports.razor 文件添加一个 @using 语句,使 Microsoft.AspNetCore.Components.Authorization 命名空间在组件之间可用:

@using Microsoft.AspNetCore.Components.Authorization;

Router 组件定义中确认或更改路由视图组件为 AuthorizeRouteViewRouter 组件的位置因应用类型而异。 如果不知道组件在项目中的位置,请使用搜索功能来查找组件。

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

注意

从启用了身份验证的某个 Blazor 项目模板创建 Blazor 应用时,该应用包含 AuthorizeRouteView 组件。 有关详细信息,请参阅 ASP.NET Core Blazor 身份验证和授权,以及文章的使用 Router 组件自定义未经授权的内容部分中提供的其他信息。

Router组件所在的位置:

Router 组件的位置因应用类型而异。 如果不知道组件在项目中的位置,请使用搜索功能来查找组件。

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

注意

从启用了身份验证的某个 Blazor 项目模板创建 Blazor 应用时,该应用包含 AuthorizeRouteViewCascadingAuthenticationState 组件。 有关详细信息,请参阅 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)));
    }
}

注意

上述创建了新 ClaimsIdentity 的代码使用通过 C# 12 (.NET 8) 引入的简化集合初始化。 有关详细信息,请参阅集合表达式 - C# 语言参考

在组件中:

@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。 使用本部分后面的其他配置,可以将 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.csStartup.ConfigureServices 中,在依赖项注入容器中注册 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;
    }
}

注意

上述创建了新 ClaimsIdentity 的代码使用通过 C# 12 (.NET 8) 引入的简化集合初始化。 有关详细信息,请参阅集合表达式 - C# 语言参考

其他资源