Blazor AuthenticationStateProvider 使用教程

来源:这里教程网 时间:2026-02-21 17:33:25 作者:

Blazor 的

AuthenticationStateProvider
是实现自定义身份验证逻辑的核心组件,它负责向整个应用提供当前用户的认证状态(比如是否已登录、用户身份信息等)。默认情况下,Blazor Server 和 Blazor WebAssembly 的基础模板已集成 Identity 或 JWT 认证,但若需对接自有登录系统、Token 存储在 localStorage、或需要手动触发状态刷新,你就得自定义一个
AuthenticationStateProvider

理解 AuthenticationStateProvider 的作用

它不是“做登录”的工具,而是“广播登录状态”的服务。Blazor 组件(如

AuthorizeView
AuthorizeRouteView
)会订阅它的状态变更,从而动态显示/隐藏内容或跳转路由。它内部维护一个
Task<authenticationstate></authenticationstate>
,并通过
NotifyAuthenticationStateChanged
方法通知所有监听者状态已更新。

关键点:

必须注册为 Scoped(Blazor Server)或 Singleton(Blazor WebAssembly),且早于
AuthenticationStateProvider
的消费者(如
CascadingAuthenticationState
)注册
重写
GetAuthenticationStateAsync()
返回当前状态(同步或异步获取用户信息)
调用
NotifyAuthenticationStateChanged(Task<authenticationstate>)</authenticationstate>
才能触发 UI 更新

手写一个基于 localStorage 的 Provider(WebAssembly 场景)

适用于 JWT 登录后把 token 存在浏览器 localStorage,页面刷新后仍需恢复登录态的场景。

步骤如下:

新建类继承
AuthenticationStateProvider
,例如
CustomAuthStateProvider
注入
IJSRuntime
用于读取 localStorage 中的 token
GetAuthenticationStateAsync()
中解析 token(可用
System.IdentityModel.Tokens.Jwt
解码,或简单检查是否存在)并构造
ClaimsPrincipal
暴露一个
MarkUserAsAuthenticated(string token)
方法,保存 token 并通知状态变更
暴露一个
Logout()
方法,清除 token 并通知未登录状态

注意:WebAssembly 中无法直接访问 HttpContext,所以不能依赖服务端 Session;token 过期校验建议在每次请求前由 HttpClient 拦截器处理,而非全靠 Provider。

触发状态更新的正确方式

别在登录成功后只改内部字段就完事——UI 不会响应。必须调用

NotifyAuthenticationStateChanged

常见错误写法:

❌ this._currentUser = new ClaimsPrincipal(identity); // 不会刷新 UI

正确做法:

构造新的
AuthenticationState
实例(含新
ClaimsPrincipal
调用
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal)))
如果操作是异步的(如从 API 获取用户信息),可直接返回该异步 Task

与路由和组件配合使用

确保

App.razor
中已包裹
CascadingAuthenticationState

<CascadingAuthenticationState>
  <Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
      <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
      <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
      <PageTitle>Not found</PageTitle>
      <LayoutView Layout="@typeof(MainLayout)">
        <p role="alert">Sorry, there's nothing at this address.</p>
      </LayoutView>
    </NotFound>
  </Router>
</CascadingAuthenticationState>

之后你就能在任意组件中使用:

<authorizeview>...</authorizeview>
根据角色/策略切换内容
@attribute [Authorize]
控制页面访问权限
@inject AuthenticationStateProvider AuthStateProvider
手动获取当前状态(不推荐频繁调用,优先用
AuthorizeView

基本上就这些。不复杂但容易忽略 Notify 通知和生命周期注册时机,踩坑多在这两处。

相关推荐