如何在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 ツ
相关产品推荐
相关产品推荐

