ASP.NET Core 5中IOperationFilter如何判断Action是否允许匿名访问
问题原因
你现有代码的问题在于:只有当授权过滤器/匿名过滤器被注册到过滤器管道(比如全局注册、或者通过[TypeFilter]等方式注册)时,才会出现在FilterDescriptors集合中。如果只是直接在Controller/Action上加[Authorize]、[AllowAnonymous]特性,没有额外做过滤器注册的话,FilterDescriptors里是找不到对应过滤器实例的,所以两个变量都会返回false。
正确实现方案
直接从ControllerActionDescriptor的方法和所属类的特性中做判断,特性的优先级符合ASP.NET Core的默认规则:Action级特性优先级高于Controller级特性。
实现代码
public class AddTenantHeaderParameterOperationFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { // 先转成ControllerActionDescriptor获取Controller和Action的元数据 if (context.ApiDescription.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor) { // 非Controller接口(比如Minimal API)可以按需处理,这里直接跳过 return; } // 优先判断是否有AllowAnonymous特性:Action级优先,其次Controller级 var hasAllowAnonymous = controllerActionDescriptor.MethodInfo.GetCustomAttributes(true) .Any(attr => attr is IAllowAnonymous) || controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(true) .Any(attr => attr is IAllowAnonymous); if (hasAllowAnonymous) { return; } // 判断是否需要授权:Action有[Authorize] 或 Controller有[Authorize] var hasAuthorize = controllerActionDescriptor.MethodInfo.GetCustomAttributes(true) .Any(attr => attr is IAuthorizeData) || controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes(true) .Any(attr => attr is IAuthorizeData); // 如果你启用了全局授权策略(比如Program里加了app.MapControllers().RequireAuthorization()) // 那不需要判断hasAuthorize,只要没有AllowAnonymous就需要授权,直接注释掉下面的判断即可 if (!hasAuthorize) { return; } // 你的添加头部参数逻辑 operation.Parameters ??= new List<OpenApiParameter>(); operation.Parameters.Add(new OpenApiParameter { Name = "X-TenantId", In = ParameterLocation.Header, Required = true, Schema = new OpenApiSchema { Type = "string" } }); } }
补充说明
如果你的项目用了Minimal API,需要额外处理EndpointMetadata里的特性,逻辑和上面一致,从context.ApiDescription.ActionDescriptor.EndpointMetadata里判断是否有IAllowAnonymous和IAuthorizeData即可。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

