自定义授权过滤最小 API .Net 6

Bee*_*eeg 3 c# asp.net .net-6.0 minimal-apis

我正在探索 .Net 6 中的最小 API,并尝试将自定义授权过滤器应用到端点(通过属性或扩展)。但在我看来,我做错了什么,或者它根本就不是为了以这种方式工作而设计的(如果是这样,那就太可悲了)。除了最小 API 中属性的默认用法之外,在文档中找不到任何内容[Authorize]

这是过滤器

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CustomAuthorizeAttribute : Attribute, IAuthorizationFilter
{
    //Checking tokens
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试在控制器级别应用它,它工作得很好

[CustomAuthorize]
public class CustomController : ControllerBase
{
    //Necessary routing
}
Run Code Online (Sandbox Code Playgroud)

但是如果我切换到 Minimap API 符号并尝试使用属性

app.MapGet("/customEndpoint", 
        [CustomAuthorize] async ([FromServices] ICustomService customService, Guid id) => 
            await customService.GetCustomStuff(id));
Run Code Online (Sandbox Code Playgroud)

甚至是扩展方法

app.MapGet("/customEndpoint", 
        async ([FromServices] ICustomService customService, Guid id) => 
            await customService.GetCustomStuff(id)).WithMetadata(new CustomAuthorizeAttribute());
Run Code Online (Sandbox Code Playgroud)

它就是行不通。过滤器甚至没有被构造。

我错过了什么或做错了什么?提前谢谢

Blo*_*mer 9

您可以在.NET 6.0中为Minimal API编写自定义授权过滤器

以下是我倾向于采用的方法 - 在 ASP.NET Core 中使用基于策略的授权

第 1 步:创建需求

需求实现IAuthorizationRequirement

public class AdminRoleRequirement : IAuthorizationRequirement
{
     public AdminRoleRequirement(string role) => Role = role;
     public string Role { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

注意:需求不需要有数据或属性。

第 2 步:创建需求处理程序

需求处理程序实现AuthorizationHandler<T>

 public class AdminRoleRequirementHandler : AuthorizationHandler<AdminRoleRequirement>
 {
    public AdminRoleRequirementHandler(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Value == requirement.Role))
        {
            context.Succeed(requirement);
        }
        else
        {

            _httpContextAccessor.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
            _httpContextAccessor.HttpContext.Response.ContentType = "application/json";
            await _httpContextAccessor.HttpContext.Response.WriteAsJsonAsync(new { StatusCode = StatusCodes.Status401Unauthorized, Message = "Unauthorized. Required admin role." });
            await _httpContextAccessor.HttpContext.Response.CompleteAsync();

            context.Fail();

        }

    }
    private readonly IHttpContextAccessor _httpContextAccessor;
}
Run Code Online (Sandbox Code Playgroud)

注意:HandleRequirementAsync方法没有返回值。成功或失败的状态通过调用context.Succeed(IAuthorizationRequirement requirement)并传递已成功验证的需求来指示,或者通过调用context.Fail()来指示AuthorizationHandlerContext.HasSucceeded即使满足所有要求也永远不会返回 true。

步骤 3:在授权服务中配置您的策略

 builder.Services.AddAuthorization(o =>
 {
        o.AddPolicy("AMIN", p => p.AddRequirements(new AdminRoleRequirement("AMIN")));
 });
Run Code Online (Sandbox Code Playgroud)

第 4 步:将您的需求处理程序添加到 DI

 builder.Services.AddSingleton<IAuthorizationHandler, AdminRoleRequirementHandler>();
Run Code Online (Sandbox Code Playgroud)

步骤 5:将策略应用到端点

 app.MapGet("/helloworld", () => "Hello World!").RequireAuthorization("AMIN");
Run Code Online (Sandbox Code Playgroud)

  • 唯一的问题是 IHttpContextAccessor 的注入。授权处理程序不应该编写响应... (2认同)