我们最常用的认证系统是Cookie认证,通常用一般需要人工登录的系统,用户访问授权范围的url时,会自动Redirect到Account/Login,登录后把认证结果存在cookie里。
系统只要找到这个cookie就认为这个web用户是已经登录的了。
通常的代码段是这样的,StartUp.cs
services.AddAuthentication(options =>{ ???options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; ???options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;}).AddCookie();
public async Task<IActionResult> Login(IFormCollection form) ???????{ ???????????string userName = form["txtLoginId"]; ???????????string pwd = form["txtPwd"]; ???????????if (Validate(userName, pwd)) ???????????{ ???????????????var claimsIdentity = new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, userName) }, "Basic"); ???????????????var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); ???????????????await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal); ???????????????return Json(new { isSuccess = true, message = "登录成功" }); ???????????} ???????}
如果我们用RestFul API写接口给前端或第三方程序使用时,这种重定向登录的方式就不合适了。
最合适的方法是,前端访问一个Login接口,获得一个AccessToken,然后用这个Token去访问后端的资源, 后端验证这个token的正确性,就放行让前端访问。
一开始比较笨的方法,是在每个接口方法都加一个accessToken的字段,这样不够优雅,可以把这个token放在Header里。这就是JWT认证
JWT有什么好处?
1、支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
2、无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
4、更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.
5、去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.
6、更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
7、CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
8、性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.
9、不需要为登录页面做特殊处理
10、基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库和多家公司的支持.
.net Core 使用Jwt认证的方法
???????????// Register the Swagger generator, defining one or more Swagger documents ???????????services.AddSwaggerGen(c => ???????????{ ???????????????c.SwaggerDoc("v1", new Info { Title = "API", Version = "v1" }); ???????????????//启用auth支持 ?????????????????????var security = new Dictionary<string, IEnumerable<string>> { { "Bearer", new string[] { } }, }; ???????????????c.AddSecurityRequirement(security); ???????????????c.AddSecurityDefinition("Bearer", new ApiKeyScheme ???????????????{ Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", ???????????????????Name = "Authorization", ???????????????????In = "header", ???????????????????Type = "apiKey" ???????????????}); ???????????}); ???????????services.AddAuthentication(options=> { ???????????????options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; ???????????????options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; ???????????}).AddJwtBearer(o => ???????????{ ???????????????o.TokenValidationParameters = new TokenValidationParameters ???????????????{ ???????????????????ValidIssuer = "Bearer", ???????????????????ValidAudience = "wr", ???????????????????IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(JwtHelper.secretKey)), ???????????????????RequireSignedTokens = true, ???????????????????// 将下面两个参数设置为false,可以不验证Issuer和Audience,但是不建议这样做。 ???????????????????ValidateAudience = false, ???????????????????ValidateIssuer = true, ???????????????????ValidateIssuerSigningKey = true, ???????????????????// 是否要求Token的Claims中必须包含 Expires ???????????????????RequireExpirationTime = true, ???????????????????// 是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比 ???????????????????ValidateLifetime = true ???????????????}; ???????????}); ???????????services.AddAuthorization(options => ???????????{ ???????????????options.AddPolicy("Client", policy => policy.RequireRole("Client").Build()); ???????????????options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build()); ???????????????options.AddPolicy("AdminOrClient", policy => policy.RequireRole("Admin,Client").Build()); ???????????});
2. 在Configure方法里,useMVC的前面增加中间件,这样每次Web请求时,会先到 JwtTokenAuth 这里处理验证token
???????????app.UseMiddleware<JwtTokenAuth>(); ???????????app.UseMvc();
3. JwtHelper.cs 里包含颁发和验证token2个方法
???????public static string IssueJWT(TokenModelJWT tokenModel) ???????{ ???????????var dateTime = DateTime.UtcNow; ???????????var claims = new Claim[] ???????????{ ???????????????new Claim(JwtRegisteredClaimNames.Jti,tokenModel.Uid.ToString()),//Id ???????????????new Claim("Role", tokenModel.Role),//角色 ???????????????new Claim(JwtRegisteredClaimNames.Iat,dateTime.ToString(),ClaimValueTypes.Integer64) ???????????}; ???????????//秘钥 ???????????var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtHelper.secretKey)); ???????????var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); ???????????var jwt = new JwtSecurityToken( ???????????????issuer: "Bearer", ???????????????claims: claims, //声明集合 ???????????????expires: dateTime.AddHours(2), ???????????????signingCredentials: creds); ???????????var jwtHandler = new JwtSecurityTokenHandler(); ???????????var encodedJwt = jwtHandler.WriteToken(jwt); ???????????return encodedJwt; ???????}
public static TokenModelJWT SerializeJWT(string jwtStr) ???????{ ???????????var jwtHandler = new JwtSecurityTokenHandler(); ???????????JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr); ???????????if (jwtToken.ValidTo < DateTime.UtcNow) ???????????????return null; ???????????object role = new object(); ; ???????????try ???????????{ ???????????????jwtToken.Payload.TryGetValue("Role", out role); ???????????} ???????????catch (Exception e) ???????????{ ???????????????Console.WriteLine(e); ???????????????throw; ???????????} ???????????var tm = new TokenModelJWT ???????????{ ???????????????Uid = int.Parse(jwtToken.Id), ???????????????Role = role != null ? role.ToString() : "", ???????????}; ???????????return tm; ???????}
4. JwtTokenAuth.cs 中间件验证token,并增加User到httpContext,表示已登录
???????public Task Invoke(HttpContext httpContext) ???????{ ???????????//检测是否包含‘Authorization‘请求头 ???????????if (!httpContext.Request.Headers.ContainsKey("Authorization")) ???????????{ ???????????????return _next(httpContext); ???????????} ???????????var tokenHeader = httpContext.Request.Headers["Authorization"].ToString(); ???????????TokenModelJWT tm = JwtHelper.SerializeJWT(tokenHeader); ???????????if (tm != null) ???????????{ ???????????????//授权 ???????????????var claimList = new List<Claim>(); ???????????????var claim = new Claim(ClaimTypes.Role, tm.Role); ???????????????claimList.Add(claim); ???????????????var identity = new ClaimsIdentity(claimList); ???????????????var principal = new ClaimsPrincipal(identity); ???????????????httpContext.User = principal; ???????????} ???????????return _next(httpContext); ???????}
把旧系统迁移到.Net Core 2.0 日记 (18) ?--JWT 认证(Json Web Token)
原文地址:https://www.cnblogs.com/zitjubiz/p/net_core_daily_18_JWT.html