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

如何使自定义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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 06:41:31