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

GraphQL应用中如何让鉴权优先于数据注解验证?

GraphQL中让鉴权优先于DataAnnotations验证的解决方案

问题场景

在使用DataAnnotatedModelValidations包的GraphQL应用中,当前执行Mutation时数据验证优先级高于鉴权。当用户无所需权限且输入无效时,预期返回未授权错误,但实际先返回验证错误;仅当输入合法时才返回未授权错误。需要实现无权限时,无论输入是否错误,API都返回“用户未授权...”错误的效果。

相关代码配置

Program.cs

builder.Services.AddAuthorization();

builder.Services
    .AddGraphQLServer()
    .AddDataAnnotationsValidator()
    .AddMutationType<Mutation>()
    .AddMutation<UserMutations>()
    .AddDefaultTransactionScopeHandler();
    
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapGraphQL("/");
app.Run();  

UserMutations.cs

[ExtendObjectType(typeof(Mutation))]
public class UserMutations
{
   [Authorize(Roles ="Admin")]
   public async  Task<User> CreateUserAsync(CreateUserInput input,
    [Service] UserService service
   ){
      await service.CreateUserAsync(input);
   
   }
}

CreateUserInput.cs

using System.ComponentModel.DataAnnotations;

public class CreateUserInput{
    
    [MaxLength(8)]
    public string UserName{get;set;}
    
    [MaxLength(15)]
    public string FirstName{get;set;}
    
    [MaxLength(15)]
    public string LastName{get;set;}
}

解决方案

要让鉴权流程优先于数据验证,可通过自定义验证器调整执行顺序,确保鉴权逻辑先触发:

方法:自定义优先鉴权的验证器

  1. 修改Program.cs配置
    移除默认的AddDataAnnotationsValidator,改用自定义验证过滤器:
builder.Services.AddAuthorization();

builder.Services
    .AddGraphQLServer()
    .AddMutationType<Mutation>()
    .AddMutation<UserMutations>()
    .AddDefaultTransactionScopeHandler()
    // 替换为自定义验证配置
    .AddValidation(options =>
    {
        options.Validator = new PrioritizedAuthorizationValidator();
    });
    
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapGraphQL("/");
app.Run();  
  1. 实现PrioritizedAuthorizationValidator
    这个验证器会先检查字段的鉴权属性,失败直接返回未授权错误,通过后再执行数据验证:
using System.ComponentModel.DataAnnotations;
using HotChocolate.Validation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using System.Linq;
using System.Threading.Tasks;

public class PrioritizedAuthorizationValidator : IInputValidator
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly DataAnnotationsInputValidator _innerValidator;

    public PrioritizedAuthorizationValidator(IAuthorizationService authorizationService, IHttpContextAccessor httpContextAccessor)
    {
        _authorizationService = authorizationService;
        _httpContextAccessor = httpContextAccessor;
        _innerValidator = new DataAnnotationsInputValidator();
    }

    public async ValueTask<IReadOnlyList<IValidationError>> ValidateAsync(InputValidationContext context)
    {
        // 提取当前字段的Authorize属性
        var authorizeAttributes = context.Field.Member.GetCustomAttributes(typeof(AuthorizeAttribute), true)
            .Cast<AuthorizeAttribute>();

        foreach (var authAttr in authorizeAttributes)
        {
            var httpContext = _httpContextAccessor.HttpContext;
            if (httpContext == null)
            {
                return new[] { new ValidationError("无法获取请求上下文,鉴权失败") };
            }

            // 构建授权策略并执行检查
            var policy = string.IsNullOrEmpty(authAttr.Policy) 
                ? new AuthorizationPolicyBuilder().RequireRoles(authAttr.Roles.Split(',')).Build() 
                : new AuthorizationPolicyBuilder().AddRequirements().Build();
            
            var authResult = await _authorizationService.AuthorizeAsync(httpContext.User, null, policy);
            
            if (!authResult.Succeeded)
            {
                // 鉴权失败直接返回错误,跳过数据验证
                return new[] { new ValidationError("用户未授权,无法执行此操作") };
            }
        }

        // 鉴权通过后执行数据验证
        return await _innerValidator.ValidateAsync(context);
    }
}

关键原理

GraphQL的验证器默认按注册顺序执行,默认的DataAnnotationsValidator会先于鉴权逻辑触发。通过自定义验证器,我们在数据验证前插入鉴权检查,一旦鉴权失败就直接返回错误,跳过后续验证步骤,实现权限优先的需求。

内容的提问来源于stack exchange,提问作者Secler developer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 23:30:12