【发布时间】:2021-04-01 06:00:10
【问题描述】:
我编写了一个使用 JWTBearer 身份验证系统的 ASP.NET Core 3.1 API。当我从 Postman 调用 API 时,这个系统运行良好,但我不知道如何通过我自己的应用程序或 ASP.NET Core 3.1 MVC 网站调用它。这是 API 的配置:
API 配置:
在 Startup.cs ConfigrationServices 方法中,我添加了这段经典代码:
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = true;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5),
};
});
然后我在 Configure 方法中添加了中间件app.UseAuthentication();。
现在我有一个 UsersController.cs 和一个 SignIn 方法,如果凭据正确,该方法将 JWT 作为字符串返回。
最后,我添加了一个简单的带有[Authorize] 标签的GetUsers() 方法来测试JWT 身份验证,如下所示:
// GET: api/Users
[Authorize(Roles = "Administrator")]
[HttpGet]
public async Task<ActionResult<IEnumerable<User>>> GetUsers()
{
return await _context.Users.ToListAsync();
}
通过邮递员,一切正常。我在 POST 中调用 api/Users/SignIn url,将我的凭据作为 JSON 传递。我用 200 StatusCode 取回我的令牌。
然后我在 GET 中调用 api/Users,将之前获得的 JWT 传递给 Postman 设置 Authorization > Type : Bearer Token。我的 API 返回一个包含我要求的所有数据的成功代码。 API 端一切正常。
MVC 网站配置:
为了简化与 API 的讨论,我写了一个 Class Library 和一个 ClientService.cs 类。
Int ClientService.cs,我有这段简化的代码,它成功地从 API 获取数据:
public async Task<string> GetPage(string model)
{
var request =
new HttpRequestMessage(
HttpMethod.Get,
_baseAddress +
model);
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
如果我使用它,假设从api/something 获取信息如下:var smth = await GetPage("something") 或任何其他AllowAnonymous 方法,它将正常工作。
但如果我想让它使用Authorize 方法,我实际上在发送请求之前添加了这段代码:
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
令牌变量包含我在代码中硬写的用于测试目的的 JWT。一切正常。
所以现在我显然在尝试避免硬写 JWT。我决定将它存储在客户端的 HttpOnly Cookie 以及 ASP.NET Core 的 AntiForgeryToken 本机函数中。我写了这段代码来存储cookie:
private void Authenticate(string token)
{
Response.Cookies.Append(
"JWT",
token,
new CookieOptions()
{
HttpOnly = true,
Secure = true,
}
);
}
现在我被困在这里了。因为我将它用作服务,所以我的ClientService 对我的所有用户都是一样的。所以我无法将令牌存储在某处并将其传递给每个请求的新创建的客户端。
在调用ClientService 之前,我尝试将 JWT 添加到标头,如下所示:
public async Task<ActionResult> Index()
{
Request.Headers.Add("Authorization", "Bearer " + Request.Cookies["JWT"]);
var users = await ClientService.GetUsersAsync();
//GetUsersAsync() simply call GetPage("users") method and deserialize the JSON returned as a List<User>
return View(users);
}
但是因为我的ClientService 创建了自己的客户端,每次我使用此代码从 API 请求一些数据时都会发送自己的请求:
var request =
new HttpRequestMessage(
HttpMethod.Get,,
_baseAddress +
model);
var client = _clientFactory.CreateClient();
我之前添加的标头没有传递给 API。
一个简单的解决方案是重写我所有的ClientService 方法以接受Token 参数,但这似乎是多余且痛苦的。
将令牌传递给我的 API 的最佳和最简单的解决方案是什么?
【问题讨论】:
标签: c# jwt asp.net-core-webapi asp.net-core-3.1