在 .net 核心 web api 中存储 JWT 令牌的位置?
Posted
技术标签:
【中文标题】在 .net 核心 web api 中存储 JWT 令牌的位置?【英文标题】:Where to store JWT Token in .net core web api? 【发布时间】:2019-04-26 14:41:37 【问题描述】:我正在使用 web api 来访问数据,并且我想对 web api 进行身份验证和授权。为此,我正在使用 JWT 令牌身份验证。但我不知道应该在哪里存储访问令牌?
我想做什么?
1)登录后存储令牌
2)如果用户想访问web api的任何方法,检查token对该用户是否有效,如果有效则授予访问权限。
我知道两种方法
1) 使用 cookie
2)sql server 数据库
从上面存储令牌的更好方法是哪一种?
【问题讨论】:
您能否进一步解释您的用例。您是否想在您的 webapi 上强制执行身份验证,以便您的调用者在调用您的控制器和操作之前需要进行身份验证,或者您的 webapi 是否正在调用另一个需要对您的调用进行身份验证的系统?如果您正在尝试实现先前的选项,则无需担心如果您已完成自定义中间件,除非您正在考虑拆分应用程序的多个实例并且您需要共享会话(不知道为什么要使用会议虽然) 但是,如果您询问如何在成功验证后将令牌交付给调用者,您有两种选择。使用标准 owin 中间件使用承载来处理身份验证,然后您可以在响应中返回 jwt(风险在于您的最终客户端以保护令牌)或配置中间件以使用 cookie 身份验证并仅返回带有标头 Set 的 cookie cookie 然后您的客户端可以保存 cookie 而不必担心任何其他应用程序能够访问其信息 你认为为什么需要将 jwt 存储在任何地方? 通过比较token来验证用户是否有效 【参考方案1】:我不熟悉将用户令牌存储在后端应用程序中,我将快速检查它是如何工作的不需要在你身边存放任何东西。
如果您使用 cookie,那么您只需要配置中间件来验证 cookie 的有效性,如果它出现在用户/消费者的标头中,如果不可用或已过期或无法解析,您只需拒绝请求和用户甚至不会点击任何受保护的控制器和操作。这是一个非常简化的 cookie 方法。(我仍在使用它进行开发,尚未在生产中进行测试,但现在使用 JS 客户端和 Postman 在本地工作得很好)
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
options.Cookie.Name = "yourCookieName";
options.Cookie.SameSite = SameSiteMode.None;//its recommended but you can set it to any of the other 3 depending on your reqirements
options.Events = new Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents
OnRedirectToLogin = redirectContext =>//this will be called if an unauthorized connection comes and you can do something similar to this or more
redirectContext.HttpContext.Response.StatusCode = 401;
return Task.CompletedTask;
,
OnValidatePrincipal = context => //if a call comes with a valid cookie, you can use this to do validations. in there you have access to the request and http context so you should have enough to work with
var userPrincipal = context.Principal;//I'm not doing anything with this right now but I could for instance validate if the user has the right privileges like claims etc
return Task.CompletedTask;
;
);
显然这将被放置或调用在您启动的 ConfigureServices 方法中以注册身份验证
然后在 Startup 的 Configure 方法中,您可以像这样连接身份验证
app.UseAuthentication();
之前
app.UseMvc()
【讨论】:
【参考方案2】:或者,如果您只是想使用 JWT 进行身份验证,则实现会略有不同
services.AddAuthentication(options =>
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
).AddJwtBearer(options =>
options.Events = new JwtBearerEvents
OnTokenValidated = context =>
var user = context.Principal.Identity.Name;
//Grab the http context user and validate the things you need to
//if you are not satisfied with the validation fail the request using the below commented code
//context.Fail("Unauthorized");
//otherwise succeed the request
return Task.CompletedTask;
;
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey("MyVeryStrongKeyHiddenFromAnyone"),
ValidateIssuer = false,
ValidateAudience = false
;
);
在使用 MVC 之前仍然应用使用身份验证。
[请注意,这些是非常简化的示例,您可能需要进一步加强安全性并实施最佳实践,例如使用强密钥、可能从环境中加载配置等]
那么实际的身份验证操作,比如在 AuthenticationController 中可能类似于
[Route("api/[controller]")]
[Authorize]
public class AuthenticationController : Controller
[HttpPost("authenticate")]
[AllowAnonymous]
public async Task<IActionResult> AuthenticateAsync([FromBody]LoginRequest loginRequest)
//LoginRequest may have any number of fields expected .i.e. username and password
//validate user credentials and if they fail return
//return Unauthorized();
var claimsIdentity = new ClaimsIdentity(new Claim[]
//add relevant user claims if any
, "Cookies");
var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
await Request.HttpContext.SignInAsync("Cookies", claimsPrincipal);
return Ok();
在这种情况下,我使用 cookie,因此我使用 Set Cookie 返回 HTTP 结果。如果我使用的是 JWT,我会返回类似
[HttpPost("authenticate")]
public IActionResult Authenticate([FromBody]LoginRequest loginRequest)
//validate user credentials and if they validation failed return a similar response to below
//return NotFound();
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes("MySecurelyInjectedAsymKey");
var tokenDescriptor = new SecurityTokenDescriptor
Subject = new ClaimsIdentity(new Claim[]
//add my users claims etc
),
Expires = DateTime.UtcNow.AddDays(1),//configure your token lifespan and needed
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey("MyVerySecureSecreteKey"), SecurityAlgorithms.HmacSha256Signature),
Issuer = "YourOrganizationOrUniqueKey",
IssuedAt = DateTime.UtcNow
;
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
var cookieOptions = new CookieOptions();
cookieOptions.Expires = DateTimeOffset.UtcNow.AddHours(4);//you can set this to a suitable timeframe for your situation
cookieOptions.Domain = Request.Host.Value;
cookieOptions.Path = "/";
Response.Cookies.Append("jwt", tokenString, cookieOptions);
return Ok();
【讨论】:
感谢您的解决方案,但这里的 IUserDomain 是什么...? 没问题,不用担心,这些基本上只是服务编排,有助于执行某些操作,例如访问数据库以验证用户凭据或调用内部身份验证系统。但是您是否掌握了不需要使用数据库来存储令牌的基本知识以上是关于在 .net 核心 web api 中存储 JWT 令牌的位置?的主要内容,如果未能解决你的问题,请参考以下文章
使用 JWT 令牌保护 asp.net 核心 Web api 时如何从 Azure AD 获取用户
text 使用ASP.NET Core 2 Web API,Angular 5,.NET核心身份和Facebook登录进行JWT身份验证
AzureAD 的 JWT 在 .NET 核心 API 中提供 403 Forbidden