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

Blazor:Windows认证后在WhenAuthenticated事件调用自定义AuthenticationStateProvider

解决方案

核心思路

在Windows认证完成的事件中,通过依赖注入获取自定义AuthenticationStateProvider实例,执行自定义授权流程后更新ClaimsPrincipal并通知Blazor组件状态变更,以此实现基于角色的授权。


步骤1:改造自定义Negotiate事件类,注入AuthenticationStateProvider

修改你的CMAPNegotiateEvents,添加自定义AuthenticationStateProvider的构造函数注入,在认证完成事件中执行自定义授权逻辑:

public class CMAPNegotiateEvents : NegotiateEvents
{
    private readonly IWebHostEnvironment _env;
    private readonly CustomAuthenticationStateProvider _customAuthStateProvider;

    // 构造函数注入自定义AuthenticationStateProvider
    public CMAPNegotiateEvents(IWebHostEnvironment env, CustomAuthenticationStateProvider customAuthStateProvider)
    {
        _env = env;
        _customAuthStateProvider = customAuthStateProvider;
    }

    // 对应Windows认证完成的事件(替代你提到的WhenAuthenticated)
    public override async Task AuthenticateResultReceived(AuthenticateResultReceivedContext context)
    {
        if (context.Result.Succeeded)
        {
            // 1. 获取Windows认证后的基础ClaimsPrincipal
            var windowsPrincipal = context.Principal;

            // 2. 执行自定义应用授权流程,比如调用内部服务获取角色
            var authorizedPrincipal = await RunCustomAuthorization(windowsPrincipal);

            // 3. 调用自定义Provider更新Principal并通知Blazor
            await _customAuthStateProvider.UpdateAuthenticatedPrincipal(authorizedPrincipal);

            // 可选:更新HttpContext的Principal,供后续中间件使用
            context.Principal = authorizedPrincipal;
        }
    }

    // 自定义授权流程实现(替换为你的实际逻辑)
    private async Task<ClaimsPrincipal> RunCustomAuthorization(ClaimsPrincipal windowsPrincipal)
    {
        var windowsUsername = windowsPrincipal.Identity?.Name;
        if (string.IsNullOrEmpty(windowsUsername))
            throw new InvalidOperationException("无法获取Windows认证用户名");

        // 调用你的自定义认证服务获取角色列表
        var userRoles = await FetchRolesFromCustomAuthSystem(windowsUsername);

        // 基于Windows身份创建新的ClaimsIdentity,添加自定义角色
        var customIdentity = new ClaimsIdentity(windowsPrincipal.Identity);
        foreach (var role in userRoles)
        {
            customIdentity.AddClaim(new Claim(ClaimTypes.Role, role));
        }

        return new ClaimsPrincipal(customIdentity);
    }

    // 模拟调用自定义认证服务的方法
    private async Task<List<string>> FetchRolesFromCustomAuthSystem(string username)
    {
        // 替换为你的实际接口调用逻辑
        return await Task.FromResult(new List<string> { "Admin", "ContentEditor" });
    }
}

步骤2:完善自定义AuthenticationStateProvider

确保你的自定义Provider包含更新Principal并通知状态变更的方法:

public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
    private ClaimsPrincipal _currentPrincipal = new ClaimsPrincipal(new ClaimsIdentity());

    public override Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        return Task.FromResult(new AuthenticationState(_currentPrincipal));
    }

    // 自定义方法:更新Principal并触发Blazor状态变更
    public async Task UpdateAuthenticatedPrincipal(ClaimsPrincipal newPrincipal)
    {
        _currentPrincipal = newPrincipal;
        // 通知所有监听认证状态的组件更新
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }
}

步骤3:在Program.cs中正确注册服务

确保自定义Provider和Negotiate事件的依赖注入配置正确:

// 注册自定义AuthenticationStateProvider
builder.Services.AddScoped<CustomAuthenticationStateProvider>();
// 替换默认的AuthenticationStateProvider为自定义实现
builder.Services.AddScoped<AuthenticationStateProvider>(sp => 
    sp.GetRequiredService<CustomAuthenticationStateProvider>());

// 配置Windows认证,通过DI获取CMAPNegotiateEvents实例
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
    .AddNegotiate(options =>
    {
        // 使用工厂模式获取事件实例,确保依赖注入生效
        options.Events = sp => new CMAPNegotiateEvents(builder.Environment, 
            sp.GetRequiredService<CustomAuthenticationStateProvider>());
    });

// 启用授权中间件
builder.Services.AddAuthorization();

关键注意点

  1. 事件选择:使用AuthenticateResultReceived事件而非自定义WhenAuthenticated,这是Negotiate认证流程中官方提供的、Windows认证完成后的回调点。
  2. 状态通知:必须调用NotifyAuthenticationStateChanged,否则Blazor组件无法感知认证状态变化,基于角色的AuthorizeView等授权组件不会生效。
  3. 身份保留:基于Windows认证的ClaimsIdentity扩展角色,而非完全替换,既保留Windows认证的合法性,又添加自定义授权信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 15:16:00