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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 05:24:17