自定义 Bearer 令牌验证和用户角色授权

问题描述 投票:0回答:1

我正在工作的项目正在 .NET 6 上运行。ASP.NET Core 6 Web API 本身并不生成 JWT,而是将用户信用发送到另一个身份验证 API 并从那里检索不记名令牌。

我的目标是:当用户请求授权操作时,API 应该从 header 中获取不记名令牌并将其发送到另一个 API 进行验证,同时从令牌中获取

userId
并使用数据库验证用户角色。

目前,我已经创建了简单的自定义属性,但仍难以继续前进。目前状态:

Programs.cs

...
//app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

创建了简单的自定义属性:

public class MyAuthorize : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext httpContext)
    {   
       var token = httpContext.HttpContext.Request.Headers.Authorization.ToString().Replace("Bearer ", "");
       var jwt = new JwtSecurityTokenHandler().ReadJwtToken(token);
       var user = jwt.Claims.First(c => c.Type == "NameIdentifier")?.Value;
   }
}

并成功将自定义属性应用到控制器方法:

[ApiController]
[Route("api/myapi")]
public class MyController: ControllerBase
{
    [HttpGet("test-me")]
    [MyAuthorize]
    public async Task<IActionResult> TestMe()
    {
        // do something
        return Ok();
    }
}

在当前状态下,我找不到将服务注入到

MyAttribute
中以创建用于令牌和角色验证的自定义逻辑的方法。

我的目标是实现这样的目标:

[HttpGet("test-me")]
[MyAuthorize(Roles="Admin")]
public async Task<IActionResult> TestMe()
{
    // do something
    return Ok();
}

其中

MyAttribute
将向另一个 API 发送 http 请求以验证令牌并向数据库执行请求并验证用户角色。

c# authorization asp.net-core-webapi .net-6.0
1个回答
0
投票

所以我通过以下更改达到了我想要的结果。

自定义身份验证处理程序:

public class MyAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    public MyAuthenticationHandler (
        IOptionsMonitor<AuthenticationSchemeOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock)
    : base(options, logger, encoder, clock)
    {
        // inject services here
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        // Read token from HTTP request header
        string authorizationHeader = Request.Headers["Authorization"]!;
        if (string.IsNullOrEmpty(authorizationHeader) || !authorizationHeader.StartsWith("Bearer "))
        {
            return AuthenticateResult.Fail("no token");
        }
        // Remove "Bearer" to get pure token data
        var token = authorizationHeader.Substring("Bearer ".Length);

        try
        {
            //auth logic
            
            return AuthenticateResult.Success(ticket);
        }
        catch (Exception ex)
        {
            //oops
            return AuthenticateResult.Fail(ex);
        }            
    }
}

自定义授权处理程序:

public class MyAuthorizationHandler : AuthorizationHandler<MyRequirement>, IAuthorizationRequirement
{

    public MyAuthorizationHandler()
    {
        // inject services here
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement)
    {
        try
        {
            // do logic
            context.Succeed(requirement);
            return;
            
        }
        catch (Exception ex)
        {
            // handle error
        }
        
        context.Fail();
        return;
    }
}

Program.cs

...
builder.Services.AddScoped<IAuthorizationHandler, MyAuthorizationHandler>();
...
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddScheme<AuthenticationSchemeOptions, MyAuthenticationHandler>("Bearer", options => { });
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy(MyRolesPolicy.User, policy => policy.Requirements.Add(new MyRequirement("User")));
    options.AddPolicy(MyRolesPolicy.Admin, policy => policy.Requirements.Add(new MyRequirement("Admin")));
});
...
app.UseAuthentication();
app.UseAuthorization();
...

因此,我可以将

Authorize
属性应用于我的控制器和操作:

[Authorize(MyRolesPolicy.User)]
public class MyController : BaseController
{
    ...
}
© www.soinside.com 2019 - 2024. All rights reserved.