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

Blazor WebAssembly .NET7双认证方案下组件授权失效问题求助

Blazor WebAssembly .NET7 多认证方案授权问题解决方法

问题背景

我在使用Blazor WebAssembly .NET7时,尝试通过Secure认证方案保护Blazor页面:

  • 直接使用@attribute [Authorize(AuthenticationSchemes = CustomAuthenticationSchemesNames.Secure)]时,抛出错误:

    NotSupportedException: The authorization data specifies an authentication scheme with value 'Secure'. Authentication schemes cannot be specified for components. Microsoft.AspNetCore.Components.Authorization.AuthorizeViewCore.EnsureNoAuthenticationSchemeSpecified(IAuthorizeData[] authorizeData).

  • 改用基于Secure Scheme的SecurePolicy策略后,Razor页面可以正常生效,但Blazor组件仍无法正确限制仅通过默认Cookie Scheme认证的用户访问。

期望的授权流程:

  • 用户仅通过默认Cookie Scheme认证时,无法访问目标Blazor组件
  • 用户通过Secure Scheme认证时,可以访问目标Blazor组件
  • 用户同时通过两种Scheme认证时,也可以访问目标Blazor组件

原因分析

Blazor的默认AuthenticationStateProvider仅会使用**默认认证方案(DefaultAuthenticateScheme)**获取用户身份,不会自动处理多认证方案的验证逻辑。而Razor Page在服务器端处理授权时,会根据策略中指定的Scheme直接验证对应的认证状态,因此可以正常工作。

解决方案

步骤1:添加HttpContextAccessor服务

在Program.cs中注册IHttpContextAccessor,用于在授权逻辑中访问当前HttpContext:

builder.Services.AddHttpContextAccessor();

步骤2:创建自定义授权要求和处理程序

创建专门验证Secure Scheme认证状态的授权逻辑:

// 自定义授权要求
public class SecureAuthenticationRequirement : IAuthorizationRequirement { }

// 授权处理程序
public class SecureAuthenticationHandler : AuthorizationHandler<SecureAuthenticationRequirement>
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IAuthenticationService _authenticationService;

    public SecureAuthenticationHandler(IHttpContextAccessor httpContextAccessor, IAuthenticationService authenticationService)
    {
        _httpContextAccessor = httpContextAccessor;
        _authenticationService = authenticationService;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, SecureAuthenticationRequirement requirement)
    {
        var httpContext = _httpContextAccessor.HttpContext;
        if (httpContext == null)
        {
            context.Fail();
            return;
        }

        // 直接验证Secure Scheme的认证状态
        var secureAuthResult = await _authenticationService.AuthenticateAsync(httpContext, CustomAuthenticationSchemesNames.Secure);
        if (secureAuthResult.Succeeded)
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }
    }
}

步骤3:更新授权策略并注册处理程序

在Program.cs中调整授权策略,替换为自定义要求,并注册处理程序:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("SecurePolicy", policy =>
    {
        // 使用自定义授权要求替代原Scheme绑定的策略
        policy.Requirements.Add(new SecureAuthenticationRequirement());
    });
});

// 注册自定义授权处理程序
builder.Services.AddScoped<IAuthorizationHandler, SecureAuthenticationHandler>();

(可选)自定义AuthenticationStateProvider(如需在组件中显示Secure认证状态)

如果需要在Blazor组件中获取用户是否通过Secure Scheme认证的信息,可以自定义AuthenticationStateProvider,合并多个Scheme的身份:

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

public class CustomAuthenticationStateProvider : ServerAuthenticationStateProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IAuthenticationService _authenticationService;

    public CustomAuthenticationStateProvider(IHttpContextAccessor httpContextAccessor, IAuthenticationService authenticationService)
    {
        _httpContextAccessor = httpContextAccessor;
        _authenticationService = authenticationService;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var httpContext = _httpContextAccessor.HttpContext;
        if (httpContext == null)
        {
            return new AuthenticationState(new ClaimsPrincipal());
        }

        // 分别验证两个Scheme的认证状态
        var defaultAuthResult = await _authenticationService.AuthenticateAsync(httpContext, CookieAuthenticationDefaults.AuthenticationScheme);
        var secureAuthResult = await _authenticationService.AuthenticateAsync(httpContext, CustomAuthenticationSchemesNames.Secure);

        ClaimsPrincipal user;

        // 存在Secure认证时,合并两个Scheme的Claims
        if (secureAuthResult.Succeeded)
        {
            var combinedIdentity = new ClaimsIdentity();
            combinedIdentity.AddClaims(defaultAuthResult.Principal?.Claims ?? Enumerable.Empty<Claim>());
            combinedIdentity.AddClaims(secureAuthResult.Principal.Claims);
            user = new ClaimsPrincipal(combinedIdentity);
        }
        else
        {
            // 仅使用默认Scheme的身份
            user = defaultAuthResult.Principal ?? new ClaimsPrincipal();
        }

        return new AuthenticationState(user);
    }
}

然后在Program.cs中替换默认的Provider:

builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();

验证效果

  • 用户仅登录默认Cookie Scheme:访问Blazor组件时,自定义授权处理程序会验证Secure Scheme认证失败,拦截访问并跳转到Secure Scheme的登录页。
  • 用户登录Secure Scheme:授权处理程序验证通过,允许访问。
  • 用户同时登录两个Scheme:授权处理程序验证通过,允许访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 16:45:55