c# - 使用 JWT 令牌的 ASP.NET Core 网站到 WebApi 身份验证
问题描述
我正在开发一个 ASP.NET Core 2.2 网站,用户需要登录然后使用它。
在AccountController
我的网站中调用另一个 ASP.NET Core WebApi(带有[AllowAnonymous]
属性)从用户名和密码中获取 JWT 令牌。
AccountController
除网站内的所有控制器都将具有[Authorize("Bearer")]
检查用户是否已获得授权的属性。
我的 WebApi 也将有其他需要[Authorize("Bearer")]
的控制器,因此 JWT 令牌将在发出 http 请求时从网站传递。请参阅下面WebApi 项目中配置的Startup.cs
>方法文件:ConfigureServices()
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidIssuer = "ZZZZ",
ValidAudience = "ZZZZ",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey))
};
});
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build());
});
和Configure()
方法:
app.UseAuthentication();
ASP.NET Core WebApi - 生成 JWT 令牌:
JWTToken jwt = new JWTToken();
jwt.Token = "";
jwt.Expires = DateTime.UtcNow.AddMinutes(90);
var claims = new[]
{
new Claim(ClaimTypes.UserData, UserId)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(privateSecretKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "ZZZ",
audience: "ZZZ",
claims: claims,
expires: jwt.Expires,
signingCredentials: creds);
var tokenStr = new JwtSecurityTokenHandler().WriteToken(token);
jwt.Token = tokenStr;
return jwt;
我已经完成了生成令牌并返回 JWT 令牌的 WebApi 方法。但是我该如何处理该令牌,以便身份验证/授权在我的 ASP.NET Core 网站中工作。
[HttpPost]
public async Task<IActionResult> Login(LoginModel model)
{
var httpClient = _httpClientFactory.CreateClient(ConstantNames.WebApi);
var response = await httpClient.PostAsJsonAsync($"{ApiArea}/authenticate", model);
if (response.IsSuccessStatusCode)
{
var jwtToken = await response.Content.ReadAsAsync<JWTToken>();
/* --> WHAT DO I DO HERE? <-- */
}
else
{
ModelState.AddModelError("Password", "Invalid password");
model.Password = "";
return View(model);
}
return RedirectToAction("Index", "Home");
}
所以为了让事情变得复杂,我的项目概述是这样的:
ASP.NET Core 网站- 具有登录页面和其他控制器,带有对数据表和表单的 ajax 调用,必须获得授权 ASP.NET Core WebApi - 生成 JWT 令牌并具有用于其他 api 调用的方法,这些调用必须经过授权
我如何告诉网站如果用户未经授权,则转到我的/Account/Login
页面?
这个过程是否正确,如果不是,我还需要添加身份并为网站做不同的事情吗?
解决方案
如果您的 ASP.NET Core 网站和 ASP.NET Web API 是两个不同的网站:
- 对于 WebAPI,客户端应始终通过添加
Authorization : Bearer {access_token}
.OnMessageReceived
如果您想通过 cookie/querystring 发送它,或者注册一个处理程序 - 对于 ASP.NET Core 网站,浏览器应使用 cookie 或 JWT 作为凭据。
我不确定您的身份验证如何。
假设您选择为 ASP.NET Core 网站使用 cookie,请确保您已设置LoginPath = "/Account/Login";
// the Startup::ConfigureServices of your ASP.NET Core Website
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(o => {
o.LoginPath = "/Account/Login";
});
然后按照Camilo Terevinto的建议,您需要让用户登录:
[HttpPost]
public async Task<IActionResult> Login(LoginModel model)
{
var httpClient = _httpClientFactory.CreateClient(ConstantNames.WebApi);
var response = await httpClient.PostAsJsonAsync($"{ApiArea}/authenticate", model);
if (response.IsSuccessStatusCode)
{
var jwtToken = await response.Content.ReadAsAsync<JWTToken>();
var username = ...
var others = ...
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username),
// add other claims as you want ...
};
var iden= new ClaimsIdentity( claims, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(iden);
await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, principal);
return Redirect("/")
}
else
{
ModelState.AddModelError("Password", "Invalid password");
model.Password = "";
return View(model);
}
return RedirectToAction("Index", "Home");
}
推荐阅读
- c# - 如何将 DataGridView 图像单元格样式设置为拉伸?
- reactjs - 从子组件更改父组件中的数组
- python - 为什么 Django 表单选择字段不显示所选模型的初始值
- java - 为 Java RMI 动态注册类
- assembly - 英特尔语法汇编中的 EXTRN 是什么?
- django - 如何添加 dj_rest_auth 包的自定义用户字段
- mongodb - libPocoMongoDB.so.71:无法打开共享对象文件:没有这样的文件或目录
- node.js - 如何在 nodejs 中的 typeorm 上附加 xray?
- python - 使用子进程激活 conda 环境
- c++ - 如何多次调用具有不同参数的函数成员?