如何使自定义HasPermission Attribute在HotChocolate GraphQL端点生效
解决HotChocolate GraphQL端点自定义权限Attribute不生效的问题
你的HasPermissionAttribute基于ASP.NET Core MVC的IAuthorizationFilter接口实现,而HotChocolate拥有独立的请求处理管道,不会触发MVC的过滤器逻辑,因此该Attribute在GraphQL端点上无效。以下是两种适配HotChocolate授权体系的解决方案:
方案一:基于授权策略与需求的标准实现
该方案复用.NET Core授权系统,适配HotChocolate的授权机制,适合已有成熟授权体系的项目。
1. 定义权限需求与处理器
将原有的权限校验逻辑迁移到.NET Core授权需求与处理器中:
using Microsoft.AspNetCore.Authorization; using System.Security.Claims; // 定义权限授权需求 public class PermissionRequirement : IAuthorizationRequirement { public string[] RequiredPermissions { get; } public PermissionRequirement(params string[] requiredPermissions) { RequiredPermissions = requiredPermissions ?? throw new ArgumentNullException(nameof(requiredPermissions)); if (RequiredPermissions.Any(string.IsNullOrWhiteSpace)) { throw new ArgumentException("权限参数不能为空或空白", nameof(requiredPermissions)); } } } // 实现权限授权处理器 public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) { if (context.User.HasPermissions(requirement.RequiredPermissions)) { context.Succeed(requirement); } return Task.CompletedTask; } } // 扩展ClaimsPrincipal方法,替代原HttpContext扩展(更通用) public static class ClaimsPrincipalExtensions { public static bool HasPermissions(this ClaimsPrincipal user, string[] permissionKeys) { if (user == null) return false; var permissions = user.Claims .Where(x => x.Type == "permissions") .Select(x => x.Value) .ToList(); return permissions.Intersect(permissionKeys).Any(); } }
2. 注册授权服务与GraphQL授权
在Program.cs中注册授权策略、处理器,并启用HotChocolate授权:
var builder = WebApplication.CreateBuilder(args); // 注册授权策略与处理器 builder.Services.AddAuthorization(options => { options.AddPolicy("PermissionPolicy", policy => policy.Requirements.Add(new PermissionRequirement())); }); builder.Services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>(); // 配置GraphQL并启用授权 builder.Services.AddGraphQLServer() .AddAuthorization() // 启用HotChocolate授权支持 .AddQueryType<Query>() .AddMutationType<Mutation>(); var app = builder.Build(); // 其他中间件配置... app.MapGraphQL(); app.Run();
3. 自定义GraphQL权限Attribute(简化使用)
封装自定义Attribute,避免重复编写策略配置:
using HotChocolate.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization; [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)] public class HasGraphQLPermissionAttribute : AuthorizeAttribute { public HasGraphQLPermissionAttribute(params string[] permissions) { Policy = "PermissionPolicy"; Requirements = new IAuthorizationRequirement[] { new PermissionRequirement(permissions) }; } }
4. 在GraphQL方法中使用
[HasGraphQLPermission("CAN_ADMIN_ONLY")] public async Task<bool> CreateUser(User command) { await _mediator.Send(command); return true; }
方案二:基于HotChocolate字段描述器的轻量实现
该方案直接通过HotChocolate的字段配置拦截请求,无需依赖.NET Core授权策略,适合快速适配的场景。
1. 自定义GraphQL权限Attribute
实现ObjectFieldDescriptorAttribute,在字段配置阶段注入权限校验逻辑:
using HotChocolate.Types; using System.Reflection; using System.Security.Claims; [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public class HasGraphQLPermissionAttribute : ObjectFieldDescriptorAttribute { private readonly string[] _permissions; public HasGraphQLPermissionAttribute(params string[] permissions) { _permissions = permissions ?? throw new ArgumentNullException(nameof(permissions)); if (_permissions.Any(string.IsNullOrWhiteSpace)) { throw new ArgumentException("权限参数不能为空或空白", nameof(permissions)); } } public override void OnConfigure(IDescriptorContext context, IObjectFieldDescriptor descriptor, MemberInfo member) { // 为字段添加授权校验逻辑 descriptor.Authorize(ctx => { var user = ctx.Context.User; if (!user.HasPermissions(_permissions)) { return AuthorizationResult.Fail("权限不足"); } return AuthorizationResult.Success(); }); } } // 复用之前的ClaimsPrincipal扩展方法 public static class ClaimsPrincipalExtensions { public static bool HasPermissions(this ClaimsPrincipal user, string[] permissionKeys) { if (user == null) return false; var permissions = user.Claims .Where(x => x.Type == "permissions") .Select(x => x.Value) .ToList(); return permissions.Intersect(permissionKeys).Any(); } }
2. 在GraphQL方法中使用
无需额外注册服务,直接标记Attribute即可:
[HasGraphQLPermission("CAN_ADMIN_ONLY")] public async Task<bool> CreateUser(User command) { await _mediator.Send(command); return true; }
内容的提问来源于stack exchange,提问作者yasith rangana
相关产品推荐
相关产品推荐

