.Net Core 使用JWT权限验证
什么是JWT?
它是一种对API的保护方案(防泄漏,防攻击,防止被人篡改)
一,下载相关NuGet包
Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer(下载语句)
二,创建JwtHelpers.cs(帮助类 生成Token)
下面是JwtHelpers.cs 及注解
using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using System; using System.Collections.Generic; using System.Security.Claims; using System.Text; using System.IdentityModel.Tokens.Jwt; namespace JwtAuthDemo.Helpers { public class JwtHelpers { private readonly IConfiguration Configuration; public JwtHelpers(IConfiguration configuration) { this.Configuration = configuration; } public string GenerateToken(string userName, int expireMinutes = 30) { var issuer = Configuration.GetValue<string>("JwtSettings:Issuer"); var signKey = Configuration.GetValue<string>("JwtSettings:SignKey"); // 设定要加入到 JWT Token 中的声明资讯(Claims) var claims = new List(); // 在 RFC 7519 规格中(Section#4),总共定义了 7 个预设的 Claims,我们应该只用的到两种! //claims.Add(new Claim(JwtRegisteredClaimNames.Iss, issuer)); claims.Add(new Claim(JwtRegisteredClaimNames.Sub, userName)); // User.Identity.Name //claims.Add(new Claim(JwtRegisteredClaimNames.Aud, "The Audience")); //claims.Add(new Claim(JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddMinutes(30).ToUnixTimeSeconds().ToString())); //claims.Add(new Claim(JwtRegisteredClaimNames.Nbf, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())); // 必須为數字 //claims.Add(new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())); // 必須为數字 claims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())); // JWT ID // 网路上常看到的这个 NameId 设定是多馀的 //claims.Add(new Claim(JwtRegisteredClaimNames.NameId, userName)); // 这个 Claim 也以直接被 JwtRegisteredClaimNames.Sub 取代,所以也是多馀的 //claims.Add(new Claim(ClaimTypes.Name, userName)); // 你可以自行扩充 "roles" 加入登入者该有的角色 claims.Add(new Claim("roles", "Admin")); claims.Add(new Claim("roles", "Users")); var userClaimsIdentity = new ClaimsIdentity(claims); // 建立一组对称式加密的金钥,主要用于 JWT 签章之用 var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signKey)); // HmacSha256 有要求必須要大于128bits,所以 key 不能太短,至少要16字元以上 // https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature); // 建立 SecurityTokenDescriptor var tokenDescriptor = new SecurityTokenDescriptor { Issuer = issuer, //Audience = issuer, // 由于你的 API 受众通常没有区分特别对象,因此通常不太需要设定,也不太需要验证//NotBefore = DateTime.Now, // 预设值就是 DateTime.Now //IssuedAt = DateTime.Now, // 预设值就是 DateTime.Now Subject = userClaimsIdentity, Expires = DateTime.Now.AddMinutes(expireMinutes), SigningCredentials = signingCredentials }; // 产出所需要的 JWT securityToken 物件,并取得序列化后的 Token 结果(字串格式) var tokenHandler = new JwtSecurityTokenHandler(); var securityToken = tokenHandler.CreateToken(tokenDescriptor); var serializeToken = tokenHandler.WriteToken(securityToken); return serializeToken; } } }
三,在appsettings.json文件中写好配置
{ "JwtSettings": { "Issuer": "JwtAuthDemo", "SignKey": "1Zl4h9703IzROikK3@uK&&OEb" }, }
四,在Startup.cs中配置相关内容
1,将类注册进 .NET Core 的 DI 容器中:
services.AddSingleton();
2,让你的 ASP.NET Core 能够认得使用者传入的 Bearer Token,这部分只要设定好即可:
services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 当验证失败时,回应标头会包含 WWW-Authenticate 标头,这里会显示失败的详细错误原因 options.IncludeErrorDetails = true; // 預設值為 true,有時會特別關閉 options.TokenValidationParameters = new TokenValidationParameters { // 通过这项宣告,就可以从 "sub" 取值并设定给 User.Identity.Name NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", // 通过这项宣告,就可以从 "roles" 取值,并可让 [Authorize] 判断角色 RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role", // 一般我们都会验证 Issuer ValidateIssuer = true, ValidIssuer = Configuration.GetValue<string>("JwtSettings:Issuer"), // 通常不太需要验证 Audience ValidateAudience = false, //ValidAudience = "JwtAuthDemo", // 不验证就不需要填写 // 一般我们都会验证 Token 的有效期间 ValidateLifetime = true, // 如果 Token 中包含 key 才需要验证,一般都只有签章而已 ValidateIssuerSigningKey = false, // "1234567890123456" 应该从 IConfiguration 取得 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("JwtSettings:SignKey"))) }; });
services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "jwtlianxi119", Version = "v1" }); #region 开启Swagger认证 c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, BearerFormat = "JWT", Scheme = "Bearer" }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); #endregion });
3,在管道中设置(在 app.UseAuthorization() 之上:
app.UseAuthentication();
五,以下是 Web API 控制器的设计范例:
using System.Linq;
using JwtAuthDemo.Helpers;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace JwtAuthDemo.Controllers { [Authorize] [ApiController] public class TokenController : ControllerBase { private readonly JwtHelpers jwt; public TokenController(JwtHelpers jwt) { this.jwt = jwt; } [AllowAnonymous] [HttpPost("~/signin")] public ActionResult<string> SignIn(LoginViewModel login) { if (ValidateUser(login)) {
//login.Username用户名 var token = jwt.GenerateToken(login.Username);
//在请求头中加入token
HttpContext.Response.Headers.Add("token", token);//HttpContext.Response.Headers["token"] = token;
HttpContext.Response.Headers["Access-Control-Expose-Headers"] = "token";
return Ok(login.Username); } else { return BadRequest(); } }
//登录 private bool ValidateUser(LoginViewModel login) { return true; // TODO }
[HttpGet("~/claims")] public IActionResult GetClaims() { return Ok(User.Claims.Select(p => new { p.Type, p.Value })); } [HttpGet("~/username")] public IActionResult GetUserName() { return Ok(User.Identity.Name); } [HttpGet("~/jwtid")] public IActionResult GetUniqueId() { var jti = User.Claims.FirstOrDefault(p => p.Type == "jti"); return Ok(jti.Value); } } }
注:一套连招下来 你的jwt token权限验证就配置成功了
[AllowAnonymous]可以取消对方法的验证