ASP.NET Core Blazor 身份验证状态
注意
此版本不是本文的最新版本。 有关当前版本,请参阅本文的 .NET 9 版本。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 对于当前版本,请参阅此文的 .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
应用必须引用 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.cs
的 Startup.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 组件定义中确认或更改路由视图组件为 AuthorizeRouteView。 Router
组件的位置因应用类型而异。 如果不知道组件在项目中的位置,请使用搜索功能来查找组件。
<Router ...>
<Found ...>
<AuthorizeRouteView RouteData="routeData"
DefaultLayout="typeof(Layout.MainLayout)" />
...
</Found>
</Router>
注意
从启用了身份验证的某个 Blazor 项目模板创建 Blazor 应用时,该应用包含 AuthorizeRouteView 组件。 有关详细信息,请参阅 ASP.NET Core Blazor 身份验证和授权,以及文章的使用 Router
组件自定义未经授权的内容部分中提供的其他信息。
Router组件所在的位置:
- 确认或更改路由视图组件为 AuthorizeRouteView。
- 确认或添加 Router 组件周围的 CascadingAuthenticationState 组件。
Router
组件的位置因应用类型而异。 如果不知道组件在项目中的位置,请使用搜索功能来查找组件。
<CascadingAuthenticationState>
<Router ...>
<Found ...>
<AuthorizeRouteView RouteData="routeData"
DefaultLayout="typeof(MainLayout)" />
...
</Found>
</Router>
</CascadingAuthenticationState>
注意
从启用了身份验证的某个 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)));
}
}
注意
上述创建了新 ClaimsIdentity 的代码使用通过 C# 12 (.NET 8) 引入的简化集合初始化。 有关详细信息,请参阅集合表达式 - C# 语言参考。
在组件中:
- 注入 AuthenticationStateProvider。
- 添加用于保存用户标识符的字段。
- 添加按钮和方法,以将 AuthenticationStateProvider 强制转换为
CustomAuthStateProvider
,并使用用户的标识符调用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。 使用本部分后面的其他配置,可以将 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.cs
的 Startup.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# 语言参考。