You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自定义Blazor Server Windows AuthenticationStateProvider

解决方案

你现在必须逐页注入自定义类才能让权限生效,本质原因是角色追加逻辑写在了自定义类的构造函数里——只有类被注入实例化时,逻辑才会执行,根本没接入Blazor原生的认证状态管线。
你之前自定义AuthenticationStateProvider拿不到用户名,是因为没有复用Windows认证默认生成的认证状态,完全不需要依赖HttpContext就能拿到当前登录用户信息,按以下步骤实现即可全应用自动生效权限逻辑,不需要逐页注入:

1. 编写自定义认证状态提供器

删掉原来的CompanyAuthentication类,新建自定义类继承自AuthenticationStateProvider,通过默认的ServerAuthenticationStateProvider获取Windows认证生成的原始用户身份,再追加自定义角色逻辑:

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

public class CustomRoleAuthStateProvider : AuthenticationStateProvider
{
    private readonly ServerAuthenticationStateProvider _windowsAuthProvider;

    // 可在此注入数据库访问服务,用于查询用户角色
    public CustomRoleAuthStateProvider(ServerAuthenticationStateProvider windowsAuthProvider)
    {
        _windowsAuthProvider = windowsAuthProvider;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        // 直接获取Windows认证生成的原始认证状态,自带域/用户名信息,无需依赖HttpContext
        var authState = await _windowsAuthProvider.GetAuthenticationStateAsync();
        var user = authState.User;

        // 匿名用户直接返回原始状态,不做处理
        if (user.Identity is not { IsAuthenticated: true })
        {
            return authState;
        }

        string username = user.Identity.Name!;
        // 替换为从数据库/配置文件查询用户角色的实际逻辑
        var roles = new List<string>();
        if (username.StartsWith("admin", StringComparison.OrdinalIgnoreCase))
        {
            roles.Add("admin");
        }

        // 追加角色声明到现有用户身份
        var identity = (ClaimsIdentity)user.Identity;
        foreach (var role in roles)
        {
            identity.AddClaim(new Claim(ClaimTypes.Role, role));
        }

        // 通知认证状态更新,触发UI授权刷新
        NotifyAuthenticationStateChanged(Task.FromResult(authState));
        return authState;
    }
}

2. 注册自定义服务替换默认实现

修改Startup.cs(.NET 6+为Program.cs)的服务注册代码,删除原来的services.AddScoped<CompanyAuthentication>();,添加如下注册代码,注意放在Windows认证和Blazor基础服务注册之后:

// 原有Windows认证相关注册保留即可,不需要修改
// services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
// services.AddAuthorization();
// services.AddRazorPages();
// services.AddServerSideBlazor();

// 注册自定义认证状态提供器,替换默认实现
services.AddScoped<AuthenticationStateProvider>(sp =>
{
    var defaultWindowsAuthProvider = sp.GetRequiredService<ServerAuthenticationStateProvider>();
    return new CustomRoleAuthStateProvider(defaultWindowsAuthProvider);
});

3. 清理冗余代码

删除所有Razor页面中@inject CompanyAuthentication auth的注入代码,不需要做其他修改,原有的<AuthorizeView>组件、[Authorize]特性等所有原生授权逻辑,都会自动读取追加了角色的用户信息,全应用自动生效。


注意事项

  • 不要在Blazor代码中使用.Result、.Wait()这类同步阻塞方式调用异步方法,很容易触发线程死锁,自定义提供器中全程使用await处理异步调用即可。
  • 用户名判断建议加上StringComparison.OrdinalIgnoreCase忽略大小写,避免域账号大小写差异导致角色判断失效。
  • 如果系统运行过程中用户角色会发生变更,可以在角色更新逻辑中注入AuthenticationStateProvider,强转为CustomRoleAuthStateProvider后主动调用NotifyAuthenticationStateChanged方法,UI会自动刷新权限状态,不需要用户重新登录。
  • 不要使用HttpContext.Current,Blazor Server中HttpContext仅在初始HTTP请求阶段可用,SignalR建立连接后HttpContext就会释放,依赖它的逻辑会出现随机失效问题。

内容的提问来源于stack exchange,提问作者Ahmad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 00:24:24