自定义授权筛选最小API.Net 6



我正在探索.Net 6中的Minimal API,并尝试将自定义授权过滤器应用于端点(通过属性或扩展(。但在我看来,我做错了什么,或者根本没有设计成那样(如果是这样,那就很难过了(。在文档中找不到除Minimal API中默认使用[Authorize]属性之外的任何内容。

这是过滤器

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

如果我尝试在控制器级别应用它,它可以很好地进行

[CustomAuthorize]
public class CustomController : ControllerBase
{
//Necessary routing
}

但是如果我切换到MinimapAPI表示法并尝试使用属性

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

甚至是一种扩展方法

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

它就是不起作用。过滤器甚至还没有构建。

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

您可以在.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; }
}

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

步骤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;
}

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

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

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

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

builder.Services.AddSingleton<IAuthorizationHandler, AdminRoleRequirementHandler>();

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

app.MapGet("/helloworld", () => "Hello World!").RequireAuthorization("AMIN");

我认为您将无法在最小api中注入动作过滤器,您可以使用3种替代方法。

  1. 创建一个自定义中间件并将其注入启动类中,它将检查每个请求,并在过滤时完成预期的工作。如果只需要验证特定的控制器/端点,则可以在那里检查请求路径。

  2. 第二种方法是,您可以在像这样的最小api中注入httpcontext,从提取的jwt令牌中进行验证,如果发现不合格,则拒绝该请求。


app.MapGet("/customEndpoint", async (HttpContext context, ICustomService service) =>
{
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
if (string.isNullOrEmpty(token) || <not a valid token>) return Results.Unauthorized();    
// do some work 
return Results.Ok(result);
});

正如@Dai所建议的,你可以通过这种方式提取代币,也可以提取

AuthenticationHeaderValue.TryParse(context.Request.Headers["Authorization"], out var parsed ) && parsed.Scheme == "BearerOrWhatever" ? parsed.Parameter : null
  1. 您可以从startup.cs全局注册过滤器

最新更新