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

Blazor WASM自定义授权属性/处理器无法触发问题求助

Blazor WASM自定义授权属性/处理器实现方案

你的需求完全可行,但Blazor WASM的组件授权模型和Minimal API存在差异,直接沿用后者的实现逻辑会导致框架无法识别自定义属性,进而无法触发自定义处理器。以下是针对性的调整方案:

问题根源

  1. Blazor WASM仅识别实现IAuthorizeData接口的属性为授权属性,你原有的RequiredPermissionAttribute仅实现了自定义元数据接口,框架不会处理它。
  2. 原配置中授权策略是固定的,无法传递属性中指定的权限和逻辑运算符,导致处理器无法获取验证所需的参数。

完整实现步骤

1. 修改自定义授权属性,实现IAuthorizeData

让框架识别该属性为授权属性,并传递权限参数:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class RequiredPermissionAttribute(Permission[] permissions, LogicalOperator logicalOperator = LogicalOperator.And)
    : Attribute, IAuthorizeData, IRequiredPermissionMetadata
{
    public Permission[] Permissions { get; } = permissions;
    public LogicalOperator LogicalOperator { get; } = logicalOperator;

    // IAuthorizeData 接口成员,用于标记自定义策略
    public string? Policy { get; set; } = $"RequiredPermission_{Guid.NewGuid()}";
    public string? Roles { get; set; }
    public string? AuthenticationSchemes { get; set; }
}

2. 调整授权需求类,携带权限参数

让需求类包含验证所需的权限和逻辑运算符:

public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
    public Permission[] Permissions { get; }
    public LogicalOperator LogicalOperator { get; }

    public PermissionAuthorizationRequirement(Permission[] permissions, LogicalOperator logicalOperator)
    {
        Permissions = permissions;
        LogicalOperator = logicalOperator;
    }
}

3. 实现动态策略提供者

根据组件上的自定义属性动态生成授权策略:

public class RequiredPermissionPolicyProvider : IAuthorizationPolicyProvider
{
    private readonly DefaultAuthorizationPolicyProvider _fallbackProvider;
    private readonly IComponentContextAccessor _componentContextAccessor;

    public RequiredPermissionPolicyProvider(IOptions<AuthorizationOptions> options, IComponentContextAccessor componentContextAccessor)
    {
        _fallbackProvider = new DefaultAuthorizationPolicyProvider(options);
        _componentContextAccessor = componentContextAccessor;
    }

    public async Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
    {
        if (policyName.StartsWith("RequiredPermission_"))
        {
            var componentType = _componentContextAccessor.Context?.ComponentType;
            if (componentType != null)
            {
                var attribute = componentType.GetCustomAttribute<RequiredPermissionAttribute>();
                if (attribute != null)
                {
                    return new AuthorizationPolicyBuilder()
                        .RequireAuthenticatedUser()
                        .AddRequirements(new PermissionAuthorizationRequirement(attribute.Permissions, attribute.LogicalOperator))
                        .Build();
                }
            }
        }

        return await _fallbackProvider.GetPolicyAsync(policyName);
    }

    public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
        => _fallbackProvider.GetDefaultPolicyAsync();

    public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
        => _fallbackProvider.GetFallbackPolicyAsync();
}

4. 实现自定义授权处理器

根据需求类中的参数进行权限验证:

public class RequiredPermissionAuthorizationHandler : AuthorizationHandler<PermissionAuthorizationRequirement>
{
    // 注入用户权限查询服务(根据你的业务实现)
    private readonly IUserPermissionService _userPermissionService;

    public RequiredPermissionAuthorizationHandler(IUserPermissionService userPermissionService)
    {
        _userPermissionService = userPermissionService;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement)
    {
        if (!context.User.Identity?.IsAuthenticated ?? false)
        {
            context.Fail();
            return;
        }

        var userPermissions = await _userPermissionService.GetUserPermissionsAsync(context.User);
        bool isAuthorized = requirement.LogicalOperator switch
        {
            LogicalOperator.And => requirement.Permissions.All(p => userPermissions.Contains(p)),
            LogicalOperator.Or => requirement.Permissions.Any(p => userPermissions.Contains(p)),
            _ => false
        };

        if (isAuthorized)
            context.Succeed(requirement);
        else
            context.Fail();
    }
}

5. 注册服务到依赖注入容器

在Program.cs中替换原有的授权配置:

// 注册核心授权服务
builder.Services.AddAuthorizationCore(options =>
{
    // 设置默认 fallback 策略(可选)
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

// 注册自定义策略提供者和处理器
builder.Services.AddScoped<IAuthorizationPolicyProvider, RequiredPermissionPolicyProvider>();
builder.Services.AddScoped<IAuthorizationHandler, RequiredPermissionAuthorizationHandler>();
// 注册组件上下文访问器,用于获取当前组件的属性
builder.Services.AddScoped<IComponentContextAccessor, ComponentContextAccessor>();

6. 组件中使用自定义属性

保持你原有的使用方式即可:

@page "/global-tasks"

@attribute [RequiredPermission([Permission.ViewUsers])]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:34:50