.net 核心网站的 IAuthorizationFilter 不支持 AllowAnyonmous 属性 api

AllowAnyonmous attribute not honored in IAuthorizationFilter in .net core web api

我有一个新的 Web API 使用 .net Core 构建,带有自定义授权过滤器。我需要绕过这个过滤器来执行一些操作,但在其他情况下需要在全局范围内使用它。如何让 MyAuthFilter 遵守方法 UserController.Post 上的 [Microsoft.AspNetCore.Authorization] 属性?

授权过滤器:

public class MyAuthFilter : IAuthorizationFilter {
    public void OnAuthorization(AuthorizationFilterContext context) {
        //do some auth 
    }
}

在 Startup.cs 中全局注册 Auth 过滤器:

public void ConfigureServices(IServiceCollection services) {
    services.AddMvc(options => {
        options.Filters.Add(new MyAuthFilter());
    });
}

用户控制器上的属性修饰:

[Route("api/[controller]")]
[Authorize] //only want anonymous on single action within controller
public class UserController { 

    [HttpPost("login")]
    [AllowAnonymous] //this is not honored - MyAuthFilter.OnAuthorization is executed
        public JObject Post([FromBody] JObject userLogin) {

        }
}

内置的AuthorizeFilter有以下几行:

// Allow Anonymous skips all authorization
if (context.Filters.Any(item => item is IAllowAnonymousFilter))
{
    return;
}

FWIW,当您为这些类型的事物构建您自己的实现时,您需要小心确保您的实现考虑到它应该考虑的一切。如果您查看 AuthorizeFilter 的源代码,您会发现它做了很多您的代码可能做不到的事情。通常,最好简单地从内置实现派生并根据需要重写,而不是尝试自己实现接口。

任何关注 .Net (Core) 5.0 的人都可以通过查看 ActionDescriptors EndpointMetaData 来完成。

if (context.ActionDescriptor.EndpointMetadata.OfType<AllowAnonymousAttribute>().Any())
            return;

对于 .net core 3.1,您可以在端点上检查 IAllowAnonymous

// context is AuthorizationFilterContext
var endpoint = context.HttpContext.GetEndpoint();
if (endpoint?.Metadata?.GetMetadata<IAllowAnonymous>() != null)
{
    // do stuff
}

此更改在 here 的更新说明中进行了解释。