ASP.NET Core GraphQL Hot Chocolate自定义授权属性失效问题
解决Hot Chocolate GraphQL中自定义授权属性不生效及突变拦截方案
一、修复[CustomAuthorize]不生效的问题
Hot Chocolate有独立的授权体系,直接用ASP.NET Core原生的AuthorizeAttribute或自定义派生类不会生效,需按以下步骤调整:
1. 确保自定义属性继承Hot Chocolate的授权基类
自定义授权属性必须继承HotChocolate.Authorization.AuthorizeAttribute,而非ASP.NET Core的同名类:
using HotChocolate.Authorization; public class CustomAuthorizeAttribute : AuthorizeAttribute { public CustomAuthorizeAttribute(string policyName) : base(policyName) { // 可添加自定义初始化逻辑 } }
2. 启用Hot Chocolate的授权支持
在Program/Startup.cs中,必须同时配置ASP.NET Core授权服务和Hot Chocolate的授权扩展:
// 注册ASP.NET Core授权基础服务 builder.Services.AddAuthorization(options => { // 注册你的自定义授权策略(如果需要) options.AddPolicy("CanAddImage", policy => { policy.RequireAuthenticatedUser(); policy.RequireClaim("Permission", "Image.Add"); }); }); // 配置GraphQL服务时启用授权 builder.Services.AddGraphQLServer() .AddAuthorization() // 关键:启用Hot Chocolate授权支持 .AddMutationType<ImageMutations>() // 其他GraphQL配置(如类型、查询等)
3. 复杂场景:自定义授权处理器
如果需要访问突变参数、GraphQL上下文等信息,可实现Hot Chocolate的IMutationAuthorizationHandler:
using HotChocolate.Authorization; using HotChocolate.Execution; public class ImageAddAuthorizationHandler : IMutationAuthorizationHandler { public Task<AuthorizationResult> AuthorizeAsync(IMutationAuthorizationContext context, CancellationToken cancellationToken) { // 获取当前用户 var user = context.User; // 获取突变输入参数(假设ImageAdd的输入类型为ImageAddInput) var input = context.ArgumentValue<ImageAddInput>("input"); // 自定义授权逻辑示例 if (!user.Identity.IsAuthenticated || !user.HasClaim("Permission", "Image.Add")) { return Task.FromResult(AuthorizationResult.Failed()); } return Task.FromResult(AuthorizationResult.Success()); } } // 注册处理器到DI容器 builder.Services.AddScoped<IMutationAuthorizationHandler, ImageAddAuthorizationHandler>();
之后在突变方法上标记[Authorize(Policy = "CanAddImage")]即可关联该处理器。
二、通过中间件拦截特定突变
如果授权属性方案仍不适用,可通过两种方式拦截ImageAdd突变:
1. Hot Chocolate请求拦截器(推荐)
直接在GraphQL服务配置中添加请求拦截器,精准识别并拦截目标突变:
using HotChocolate.Language; using HotChocolate.Execution; builder.Services.AddGraphQLServer() .AddMutationType<ImageMutations>() .AddHttpRequestInterceptor(async (context, request, ct) => { // 解析GraphQL查询文档 var parser = context.RequestServices.GetRequiredService<IQueryParser>(); var document = parser.Parse(request.Query); // 查找是否存在ImageAdd突变 var mutationOp = document.Operations.FirstOrDefault(o => o.OperationType == OperationType.Mutation); if (mutationOp != null) { var hasImageAdd = mutationOp.SelectionSet.Selections .OfType<FieldNode>() .Any(f => f.Name.Value.Equals("ImageAdd", StringComparison.OrdinalIgnoreCase)); if (hasImageAdd) { // 执行授权检查 if (!context.User.Identity.IsAuthenticated || !context.User.HasClaim("Permission", "Image.Add")) { throw new GraphQLException(new Error("无权限执行ImageAdd操作", "UNAUTHORIZED")); } } } await Task.CompletedTask; });
2. ASP.NET Core全局中间件
在GraphQL中间件之前添加全局中间件,拦截所有GraphQL请求并检查目标突变:
app.Use(async (context, next) => { // 仅拦截GraphQL POST请求(默认路径为/graphql) if (context.Request.Path.Equals("/graphql", StringComparison.OrdinalIgnoreCase) && context.Request.Method == HttpMethods.Post) { // 读取请求体并重置流位置,避免后续中间件无法读取 context.Request.EnableBuffering(); var requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync(); context.Request.Body.Position = 0; // 检查是否包含ImageAdd突变 if (requestBody.Contains("mutation ImageAdd", StringComparison.OrdinalIgnoreCase)) { if (!context.User.Identity.IsAuthenticated || !context.User.HasClaim("Permission", "Image.Add")) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; await context.Response.WriteAsJsonAsync(new { error = "无权限执行该操作" }); return; } } } await next(); }); // 确保中间件在GraphQL中间件之前注册 app.UseGraphQL();
内容的提问来源于stack exchange,提问作者onur.k
相关产品推荐
相关产品推荐

