ASP.NET Core/Blazor:如何实现基于权限(非策略)的授权
Blazor WASM 动态权限授权实现方案
1. 基础定义:权限枚举与授权需求类
先定义权限操作枚举,以及用于传递授权规则的需求类:
// 权限操作枚举 public enum Permission { View, Create, Edit, Delete } // 自定义授权需求,携带页面名称和所需权限 public class PagePermissionRequirement : IAuthorizationRequirement { public string PageName { get; } public Permission RequiredPermission { get; } public PagePermissionRequirement(string pageName, Permission permission) { PageName = pageName; RequiredPermission = permission; } }
2. 实现动态授权处理器
自定义授权处理器,负责校验用户的权限Claim是否匹配需求:
public class PagePermissionHandler : AuthorizationHandler<PagePermissionRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PagePermissionRequirement requirement) { // 构造需要匹配的Claim值格式:"页面名称 - Allow 权限类型" string requiredClaimValue = $"{requirement.PageName} - Allow {requirement.RequiredPermission}"; // 检查用户是否包含对应的Permission类型Claim if (context.User.HasClaim(c => c.Type == "Permission" && c.Value == requiredClaimValue)) { context.Succeed(requirement); } return Task.CompletedTask; } }
3. 创建自定义页面授权特性
替代内置[Authorize]的自定义特性,自动关联动态授权规则:
public class PagePermissionsAttribute : AuthorizeAttribute { public PagePermissionsAttribute(string pageName, Permission permission) { // 生成唯一策略名称,用于关联动态授权需求 Policy = $"PagePermission_{pageName}_{permission}"; } } // 动态策略提供器,负责根据策略名称生成对应授权规则 public class DynamicPermissionPolicyProvider : DefaultAuthorizationPolicyProvider { private readonly IOptions<AuthorizationOptions> _options; public DynamicPermissionPolicyProvider(IOptions<AuthorizationOptions> options) : base(options) { _options = options; } public override async Task<AuthorizationPolicy?> GetPolicyAsync(string policyName) { // 识别自定义页面权限策略格式 if (policyName.StartsWith("PagePermission_")) { var parts = policyName.Split('_'); if (parts.Length == 3 && Enum.TryParse<Permission>(parts[2], out var permission)) { var policyBuilder = new AuthorizationPolicyBuilder(); policyBuilder.AddRequirements(new PagePermissionRequirement(parts[1], permission)); return policyBuilder.Build(); } } // 其他策略交给默认提供器处理 return await base.GetPolicyAsync(policyName); } }
4. 扩展AuthorizeView组件
创建支持传入页面名称和权限的自定义授权组件:
@using Microsoft.AspNetCore.Authorization @namespace YourAppNamespace.Components <AuthorizeView Policy="@PolicyName"> <Authorized>@ChildContent</Authorized> <NotAuthorized>@NotAuthorizedContent</NotAuthorized> <Authorizing>@AuthorizingContent</Authorizing> </AuthorizeView> @code { [Parameter] public string PageName { get; set; } = string.Empty; [Parameter] public Permission RequiredPermission { get; set; } [Parameter] public RenderFragment? ChildContent { get; set; } [Parameter] public RenderFragment? NotAuthorizedContent { get; set; } [Parameter] public RenderFragment? AuthorizingContent { get; set; } private string PolicyName => $"PagePermission_{PageName}_{RequiredPermission}"; }
5. 注册授权服务
在Program.cs中注册自定义授权相关服务:
// 注册授权基础服务 builder.Services.AddAuthorization(); // 注册自定义授权处理器 builder.Services.AddScoped<IAuthorizationHandler, PagePermissionHandler>(); // 替换为动态策略提供器 builder.Services.AddSingleton<IAuthorizationPolicyProvider, DynamicPermissionPolicyProvider>();
6. 认证时注入权限Claims
登录流程中,从数据库获取用户权限并添加到Claims:
// 从数据库/API获取用户权限列表 var userPermissions = await _userPermissionService.GetPermissionsForUserAsync(currentUserId); // 构建ClaimsIdentity var identity = new ClaimsIdentity(); foreach (var perm in userPermissions) { // 按照约定格式添加Permission类型Claim identity.AddClaim(new Claim("Permission", $"{perm.PageName} - Allow {perm.PermissionType}")); } // 更新认证状态 var authState = new AuthenticationState(new ClaimsPrincipal(identity)); await _authenticationStateProvider.SetAuthenticationStateAsync(authState);
使用示例
页面级授权
在Blazor页面顶部添加自定义特性:
@page "/users" @attribute [PagePermissions("Users", Permission.View)] <h3>用户管理页面</h3>
组件内局部授权
使用自定义的PageAuthorizeView组件控制局部内容显示:
<PageAuthorizeView PageName="Users" RequiredPermission="Permission.Create"> <button class="btn btn-primary">创建用户</button> <NotAuthorized> <p class="text-muted">您没有创建用户的权限</p> </NotAuthorized> </PageAuthorizeView>
内容的提问来源于stack exchange,提问作者Wade Baird
相关产品推荐
相关产品推荐

