如何在ASP.NET Core中让FluentValidation优先于授权过滤器执行
解决方案:让FluentValidation优先于自定义授权过滤器执行
在ASP.NET Core的默认过滤器执行顺序中,控制器/动作级别的授权过滤器会先于模型验证(包括FluentValidation)运行,这就是导致无效DTO仍会触发授权逻辑的原因。以下是两种可行的解决思路:
方案一:将授权逻辑迁移至动作过滤器(推荐)
动作过滤器的OnActionExecuting方法会在模型验证完成后执行,刚好满足FluentValidation优先运行的需求。
- 修改授权过滤器实现为动作过滤器
public class MyAuthorizationActionFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { // 先检查模型状态,无效则直接返回,跳过授权逻辑 if (!context.ModelState.IsValid) { context.Result = new BadRequestObjectResult(context.ModelState); return; } // 执行原有授权逻辑(数据库查询等) // Authorization logic that hits the database } public void OnActionExecuted(ActionExecutedContext context) { // 无需额外操作则留空 } }
- 更新控制器动作的过滤器标记
[HttpPost] [ServiceFilter(typeof(MyAuthorizationActionFilter))] public IActionResult Create([FromBody] MyDto myDto) { // Controller action logic }
- 在Program.cs/Startup.cs中注册过滤器
builder.Services.AddScoped<MyAuthorizationActionFilter>();
方案二:在授权过滤器中手动触发模型验证
如果必须保留IAuthorizationFilter的实现,可以在授权逻辑执行前手动触发模型绑定和FluentValidation验证,提前终止无效请求。
public class MyAuthorizationFilter : IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) { // 手动触发模型绑定与验证 context.ModelState.Clear(); var metadataProvider = context.HttpContext.RequestServices.GetRequiredService<IModelMetadataProvider>(); var validatorProvider = context.HttpContext.RequestServices.GetRequiredService<IValidatorProvider>(); var modelBinderFactory = context.HttpContext.RequestServices.GetRequiredService<IModelBinderFactory>(); var valueProviderFactory = context.HttpContext.RequestServices.GetRequiredService<IValueProviderFactory>(); // 获取DTO参数信息 var parameter = context.ActionDescriptor.Parameters.FirstOrDefault(p => p.ParameterType == typeof(MyDto)); if (parameter != null) { var modelMetadata = metadataProvider.GetMetadataForType(typeof(MyDto)); var modelBinder = modelBinderFactory.CreateBinder(new ModelBinderFactoryContext { Metadata = modelMetadata, CacheToken = parameter }); // 执行模型绑定 var bindingContext = new DefaultModelBindingContext { ActionContext = context, ModelMetadata = modelMetadata, ModelName = parameter.Name, ValueProvider = valueProviderFactory.GetValueProvider(context) }; modelBinder.BindModelAsync(bindingContext).Wait(); // 执行FluentValidation验证 if (bindingContext.Result.IsModelSet) { var validator = validatorProvider.GetValidator(typeof(MyDto)); if (validator != null) { var validationResult = validator.Validate(new ValidationContext<MyDto>((MyDto)bindingContext.Result.Model)); foreach (var error in validationResult.Errors) { context.ModelState.AddModelError(error.PropertyName, error.ErrorMessage); } } } } // 模型无效则直接返回,跳过授权逻辑 if (!context.ModelState.IsValid) { context.Result = new BadRequestObjectResult(context.ModelState); return; } // 执行原有授权逻辑(数据库查询等) // Authorization logic that hits the database } }
前置检查:确保FluentValidation服务已正确注册
无论使用哪种方案,都需要确认已在Program.cs/Startup.cs中完成FluentValidation的基础配置:
builder.Services.AddFluentValidationAutoValidation().AddFluentValidationClientsideAdapters(); builder.Services.AddScoped<IValidator<MyDto>, MyDtoValidator>();
内容的提问来源于stack exchange,提问作者esege
相关产品推荐
相关产品推荐

