我正在工作的项目正在 .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 请求以验证令牌并向数据库执行请求并验证用户角色。
所以我通过以下更改达到了我想要的结果。
自定义身份验证处理程序:
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
{
...
}