A_d*_*per 2 c# authentication jwt asp.net-web-api asp.net-core-webapi
我有一个.net core 3.1 Web API ,它是使用JWT 身份验证构建的,它与 Angular UI 集成,并且按预期工作。
以下是我的 JWT 身份验证中间件
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
// Adding Jwt Bearer
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.IncludeErrorDetails = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = false,
ValidateAudience = false,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:Secret"]))
};
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
});
Run Code Online (Sandbox Code Playgroud)
现在我需要创建更多的 Web API 方法,这些方法将由Angular UI以及一些现有的计划任务(将使用 Web API 方法的.net 控制台应用程序)使用,这些任务是为内部操作创建的,并将在背景。
我的 API 控制器用[Authorize]属性装饰。它与 Angular UI 配合得很好,其中身份验证和授权是使用 JWT 不记名令牌实现的。现在的问题是计划任务的集成,它没有获取令牌的逻辑。
如何在身份验证方面将这些控制台应用程序与 .net core Web API 集成?最简单的选择(我认为)是使用用户名“servicetask”创建一个用户登录,并根据该用户名获取令牌并执行 API 操作(但这需要更多的努力,因为控制台应用程序的数量越来越多,并且有一些也来自其他项目的应用程序)。
在这种情况下有什么办法可以处理身份验证吗?
从控制台应用程序传递一些 API 密钥并绕过 Web API 中的身份验证是一种好的做法吗?那可能吗 ?那么.net core web api中如何处理请求呢?
是否可以为这些服务帐户创建任何 JWT 角色或声明并验证它们?
请帮忙。
最好的方法是允许不记名令牌和 API 密钥授权,特别是因为您允许用户和(内部)服务访问。
添加 API 密钥中间件(我个人使用这个,使用起来很简单 - 包名称是AspNetCore.Authentication.ApiKey)和自定义验证(将 API 密钥与常规用户数据一起存储在数据库中或在配置中,无论您喜欢什么)。修改[Authorize]控制器上的属性,以便可以使用 Bearer 和 ApiKey 授权。Angular 应用程序继续使用 Bearer 身份验证,并且任何服务/控制台应用程序(或任何其他客户端,包括 Angular 客户端(如果在某些情况下需要的话))发送包含分配给该应用程序的 API 密钥的 X-Api-Key 标头。
中间件配置应该如下所示:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddApiKeyInHeader(ApiKeyDefaults.AuthenticationScheme, options =>
{
options.KeyName = "X-API-Key";
options.SuppressWWWAuthenticateHeader = true;
options.Events = new ApiKeyEvents
{
// A delegate assigned to this property will be invoked just before validating the api key.
OnValidateKey = async (context) =>
{
var apiKey = context.ApiKey.ToLower();
// custom code to handle the api key, create principal and call Success method on context. apiUserService should look up the API key and determine is it valid and which user/service is using it
var apiUser = apiUserService.Validate(apiKey);
if (apiUser != null)
{
... fill out the claims just as you would for user which authenticated using Bearer token...
var claims = GenerateClaims();
context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
context.Success();
}
else
{
// supplied API key is invalid, this authentication cannot proceed
context.NoResult();
}
}
};
})
// continue with JwtBearer code you have
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, x => ...
Run Code Online (Sandbox Code Playgroud)
这整理了Startup.cs一部分。
现在,在控制器中,您想要启用 Bearer 和 ApiKey 身份验证,修改属性,使其如下所示:
[Route("api/[controller]")]
[ApiController]
[Authorize(AuthenticationSchemes = "ApiKey, Bearer")]
public class SomeController : ControllerBase
Run Code Online (Sandbox Code Playgroud)
现在,Angular 客户端仍将以相同的方式工作,但控制台应用程序可能会像这样调用 API:
using (HttpClient client = new HttpClient())
{
// header must match definition in middleware
client.DefaultRequestHeaders.Add("X-API-Key", "someapikey");
client.BaseAddress = new Uri(url);
using (HttpResponseMessage response = await client.PostAsync(url, q))
{
using (HttpContent content =response.Content)
{
string mycontent = await content.ReadAsStringAsync();
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我看来,这种方法充分利用了AuthenticationHandler,并提供了最干净的方法来处理使用 JWT 的“常规”客户端和使用固定 API 密钥的服务,密切关注OAuth 中间件之类的东西。如果有人想从头开始构建类似的东西,基本上实现任何类型的身份验证,则有关构建自定义身份验证处理程序的更多详细信息。
当然,缺点是这些 API 密钥的安全性,即使您仅将它们用于内部服务。这个问题可以通过使用声明限制这些 API 密钥的访问范围、不对多个服务使用相同的 API 密钥并定期更改它们来解决。此外,如果不使用 SSL,API 密钥很容易被拦截 (MITM),因此请注意这一点。
| 归档时间: |
|
| 查看次数: |
3881 次 |
| 最近记录: |