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

如何在Blazor WASM中实现自定义身份验证特性?

问题场景

我需要自定义Identity角色系统,创建了Projects表并关联到UserRoles表,用户的角色是基于项目的——除了用户和角色外,还需校验项目ID这一额外字段。

我已经在Asp.NET Api端自定义了如下Authorize特性:

public class AuthAttribute : ActionFilterAttribute
{
    public string[] Roles { get; init; }
    public AuthAttribute(params string[] roles) => Roles = roles;

    public override async Task OnActionExecutionAsync(ActionExecutingContext context,ActionExecutionDelegate next)
    {
        if(!context.HttpContext.User.Identity!.IsAuthenticated)
        {
            context.Result = new UnauthorizedResult();
            return;
        }
        int projectId = int.Parse(context.HttpContext.GetHeaderValue("ProjectId"));
        var userManager = context.HttpContext.RequestServices.GetService<IUserManagerService>();
        int userId = context.HttpContext.User.Identity.GetId();
        foreach(var role in Roles)
        {
            var isHasRole = await userManager!.IsInRolAsync(userId,role,projectId);
            if(isHasRole)
                return;
        }
        context.Result = new ForbidResult();
    }
}

注:我使用JWT身份验证,从请求头获取项目ID

在客户端,我将角色和项目信息以RoleProjectClaimModel数组的形式存入JWT Claims中:

public class RoleProjectClaimModel
{
    public string Role { get; set; }
    public int ProjectId { get; set; }
}

同时项目ID已保存到本地存储,请问如何在Blazor中自定义身份验证特性?


Blazor端自定义身份验证特性实现方案

1. 定义授权要求与处理程序

Blazor中基于授权策略实现自定义逻辑更贴合框架设计,先创建自定义授权要求:

public class ProjectRoleRequirement : IAuthorizationRequirement
{
    public string[] RequiredRoles { get; }

    public ProjectRoleRequirement(params string[] requiredRoles)
    {
        RequiredRoles = requiredRoles;
    }
}

接着实现授权处理程序,从本地存储取项目ID,解析JWT中的角色-项目声明做校验:

public class ProjectRoleHandler : AuthorizationHandler<ProjectRoleRequirement>
{
    private readonly IJSRuntime _jsRuntime;

    public ProjectRoleHandler(IJSRuntime jsRuntime)
    {
        _jsRuntime = jsRuntime;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ProjectRoleRequirement requirement)
    {
        // 校验用户是否已认证
        if (!context.User.Identity.IsAuthenticated)
        {
            context.Fail();
            return;
        }

        // 从本地存储获取当前项目ID
        var projectIdStr = await _jsRuntime.InvokeAsync<string>("localStorage.getItem", "ProjectId");
        if (!int.TryParse(projectIdStr, out int projectId))
        {
            context.Fail();
            return;
        }

        // 解析JWT中的角色-项目声明
        var roleProjectClaim = context.User.FindFirst(c => c.Type == "RoleProjects")?.Value;
        if (string.IsNullOrEmpty(roleProjectClaim))
        {
            context.Fail();
            return;
        }

        var roleProjects = JsonSerializer.Deserialize<List<RoleProjectClaimModel>>(roleProjectClaim);
        if (roleProjects == null)
        {
            context.Fail();
            return;
        }

        // 校验是否拥有当前项目的指定角色
        bool hasValidRole = roleProjects.Any(r => 
            requirement.RequiredRoles.Contains(r.Role, StringComparer.OrdinalIgnoreCase) && 
            r.ProjectId == projectId);

        if (hasValidRole)
        {
            context.Succeed(requirement);
        }
        else
        {
            context.Fail();
        }
    }
}

2. 注册授权服务

在Program.cs中注册自定义授权组件和策略:

builder.Services.AddAuthorization(options =>
{
    // 按需注册不同角色组合的策略
    options.AddPolicy("ProjectAdmin", policy =>
        policy.Requirements.Add(new ProjectRoleRequirement("Admin")));
    
    options.AddPolicy("ProjectEditor", policy =>
        policy.Requirements.Add(new ProjectRoleRequirement("Editor")));
    
    // 多角色策略示例:同时拥有Admin或Editor权限
    options.AddPolicy("ProjectAdminOrEditor", policy =>
        policy.Requirements.Add(new ProjectRoleRequirement("Admin", "Editor")));
});

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

// Blazor WASM需额外注册HttpContextAccessor(若需要)
// builder.Services.AddHttpContextAccessor();

3. 封装自定义授权特性(可选)

如果想和API端一样用特性标注,可封装简化使用:

public class ProjectAuthorizeAttribute : AuthorizeAttribute
{
    public ProjectAuthorizeAttribute(params string[] roles)
    {
        Policy = $"Project_{string.Join("_", roles)}";
        // 注意:需提前在Program.cs中注册对应名称的策略,或动态生成策略逻辑
    }
}

4. 在Blazor组件中使用

组件级别授权

@attribute [ProjectAuthorize("Admin")]

<h3>仅当前项目管理员可见内容</h3>

局部内容授权

<AuthorizeView Policy="ProjectEditor">
    <Authorized>
        <button>编辑项目内容</button>
    </Authorized>
    <NotAuthorized>
        <p>您没有当前项目的编辑权限</p>
    </NotAuthorized>
</AuthorizeView>

关键注意事项

  • 确保JWT中RoleProjects声明是序列化后的RoleProjectClaimModel数组字符串
  • 本地存储的ProjectId需和API端请求头传递的保持一致
  • Blazor Server模式下,若需从HttpContext获取用户信息,需确保IHttpContextAccessor已注册

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 09:24:55