JWT是什么?校验逻辑?授权过程?这里就不过多的阐述了,直接上代码
在appsettings.json中配置jwt参数的值
SecretKey必须大于16个字符
1 { 2 "Logging": { 3 "LogLevel": { 4 "Default": "Information", 5 "Microsoft.AspNetCore": "Warning" 6 } 7 }, 8 "AllowedHosts": "*", 9 "AppSettings": { 10 //数据库连接字符串 11 "ConnectionString": "server=192.168.132.131;uid=sa;pwd=6014359wQ@!;database=MagCoreDB", 12 "JwtSetting": { 13 "Issuer": "jwtIssuer", //颁发者 14 "Audience": "jwtAudience", //可以给哪些客户端使用 15 "SecretKey": "yehjsiwkjhuhgyehsnd" //加密Key 16 } 17 } 18 }
Nuget安装以下三个包:
在web.core.model中新建类TokenModel:
1 /// <summary> 2 /// 令牌 3 /// </summary> 4 public class TokenModel 5 { 6 /// <summary> 7 /// Id 8 /// </summary> 9 public string Uid { get; set; } 10 /// <summary> 11 /// 角色 12 /// </summary> 13 public string Role { get; set; } 14 15 }
新建JwtHelper.cs帮助类
1 public class JwtHelper 2 { 3 /// <summary> 4 /// 颁发JWT字符串 5 /// </summary> 6 /// <param name="tokenModel"></param> 7 /// <returns></returns> 8 public static string IssueJwt(TokenModel tokenModel) 9 { 10 //获取Appsetting配置 11 string iss = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" }); 12 string aud = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" }); 13 string secret = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" }); 14 15 //var claims = new Claim[] //old 16 var claims = new List<Claim> 17 { 18 /* 19 * 特别重要: 20 1、这里将用户的部分信息,比如 uid 存到了Claim 中,如果你想知道如何在其他地方将这个 uid从 Token 中取出来,请看下边的SerializeJwt() 方法,或者在整个解决方案,搜索这个方法,看哪里使用了! 21 2、你也可以研究下 HttpContext.User.Claims ,具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。 22 */ 23 new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()), 24 new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"), 25 new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") , 26 //这个就是过期时间,目前是过期1000秒,可自定义,注意JWT有自己的缓冲过期时间 27 new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds()}"), 28 new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(1000).ToString()), 29 new Claim(JwtRegisteredClaimNames.Iss,iss), 30 new Claim(JwtRegisteredClaimNames.Aud,aud), 31 32 }; 33 34 // 可以将一个用户的多个角色全部赋予; 35 claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s))); 36 37 38 39 //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常) 40 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)); 41 var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); 42 43 var jwt = new JwtSecurityToken( 44 issuer: iss, 45 claims: claims, 46 signingCredentials: creds); 47 48 var jwtHandler = new JwtSecurityTokenHandler(); 49 var encodedJwt = jwtHandler.WriteToken(jwt); 50 51 return encodedJwt; 52 } 53 54 /// <summary> 55 /// 解析 56 /// </summary> 57 /// <param name="jwtStr"></param> 58 /// <returns></returns> 59 public static TokenModel SerializeJwt(string jwtStr) 60 { 61 var jwtHandler = new JwtSecurityTokenHandler(); 62 JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr); 63 object role; 64 try 65 { 66 jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role); 67 } 68 catch (Exception e) 69 { 70 Console.WriteLine(e); 71 throw; 72 } 73 var tm = new TokenModel 74 { 75 Uid = jwtToken.Id.ToString(), 76 Role = role != null ? role.ToString() : "", 77 }; 78 return tm; 79 } 80 }
在HomeController中新建Login接口来获取Token
1 /// <summary> 2 /// 获取Token 3 /// </summary> 4 /// <param name="rolename"></param> 5 /// <param name="password"></param> 6 /// <returns></returns> 7 [HttpGet] 8 [AllowAnonymous] 9 public async Task<IActionResult> Login(string rolename, string password) 10 { 11 string jwtStr = string.Empty; 12 bool suc = false; 13 14 if (rolename != null && password != null) 15 { 16 if (rolename != "Admin" && password != "123456") 17 { 18 jwtStr = "输入不正确!"; 19 } 20 else 21 { 22 // 将用户id和角色名,作为单独的自定义变量封装进 token 字符串中。 23 TokenModel tokenModel = new TokenModel { Uid = "1", Role = rolename }; 24 jwtStr = JwtHelper.IssueJwt(tokenModel);//登录,获取到一定规则的 Token 令牌 25 suc = true; 26 } 27 } 28 else 29 { 30 jwtStr = "输入不能为空!"; 31 } 32 33 return Ok(new 34 { 35 success = suc, 36 token = jwtStr 37 }); 38 }
运行项目,输入Admin,123456,获取Token:
JWT权限验证,就需要开启验证,然后输入token令牌,然后在SwaggerSetUp.cs的AddSwaggerSetup方法的AddSwaggerGen服务中,添加代码:
1 services.AddSwaggerGen(c => 2 { 3 c.SwaggerDoc("V1", new OpenApiInfo 4 { 5 // {ApiName} 定义成全局变量,方便修改 6 Version = "V1", 7 Title = $"{ApiName} 接口文档——.NetCore 6.0", 8 Description = $"{ApiName} HTTP API V1", 9 //Contact = new OpenApiContact { Name = ApiName, Email = "[email protected]", Url = new Uri("https://www.jianshu.com/u/94102b59cc2a") }, 10 //License = new OpenApiLicense { Name = ApiName, Url = new Uri("https://www.jianshu.com/u/94102b59cc2a") } 11 }); 12 c.OrderActionsBy(o => o.RelativePath); 13 14 var xmlPath = Path.Combine(AppContext.BaseDirectory, "Mag.Core.API.xml");//这个就是刚刚配置的xml文件名 15 c.IncludeXmlComments(xmlPath, true);//默认的第二个参数是false,这个是controller的注释,记得修改 16 var xmlModelPath = Path.Combine(AppContext.BaseDirectory, "Mag.Core.Model.xml");//这个就是Model层的xml文件名 17 c.IncludeXmlComments(xmlModelPath); 18 19 // 在header中添加token,传递到后台 20 c.OperationFilter<SecurityRequirementsOperationFilter>(); 21 22 #region Token绑定到ConfigureServices 23 c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme 24 { 25 Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"", 26 Name = "Authorization",//jwt默认的参数名称 27 In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中) 28 Type = SecuritySchemeType.ApiKey 29 }); 30 #endregion 31 });
运行项目,就可以看见JWT验证入口:
在SetUp文件夹里面新建注册方法AuthorizationSetup.cs
1 public static class AuthorizationSetup 2 { 3 public static void AddAuthorizationSetup(this IServiceCollection services) 4 { 5 if (services == null) throw new ArgumentNullException(nameof(services)); 6 7 // 1【授权】、这个和上边的异曲同工,好处就是不用在controller中,写多个 roles 。 8 // 然后这么写 [Authorize(Policy = "Admin")] 9 services.AddAuthorization(options => 10 { 11 options.AddPolicy("User", policy => policy.RequireRole("User").Build()); 12 options.AddPolicy("System", policy => policy.RequireRole("System").Build()); 13 options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System")); 14 15 }); 16 17 //读取配置文件 18 var symmetricKeyAsBase64 = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" }); 19 var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64); 20 var signingKey = new SymmetricSecurityKey(keyByteArray); 21 var Issuer = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" }); 22 var Audience = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" }); 23 24 25 26 // 令牌验证参数 27 var tokenValidationParameters = new TokenValidationParameters 28 { 29 ValidateIssuerSigningKey = true, 30 IssuerSigningKey = signingKey, 31 ValidateIssuer = true, 32 ValidIssuer = Issuer,//发行人 33 ValidateAudience = true, 34 ValidAudience = Audience,//订阅人 35 ValidateLifetime = true, 36 ClockSkew = TimeSpan.FromSeconds(30), 37 RequireExpirationTime = true, 38 }; 39 40 //2.1【认证】、core自带官方JWT认证 41 // 开启Bearer认证 42 services.AddAuthentication("Bearer") 43 // 添加JwtBearer服务 44 .AddJwtBearer(o => 45 { 46 o.TokenValidationParameters = tokenValidationParameters; 47 o.Events = new JwtBearerEvents 48 { 49 OnAuthenticationFailed = context => 50 { 51 // 如果过期,则把<是否过期>添加到,返回头信息中 52 if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) 53 { 54 context.Response.Headers.Add("Token-Expired", "true"); 55 } 56 return Task.CompletedTask; 57 } 58 }; 59 }); 60 61 62 63 } 64 }
在program.cs里面注册服务,开启服务
//jwt授权验证
builder.Services.AddAuthorizationSetup();
app.UseAuthentication();
在BaseApiController里面设置全局权限验证:
没有验证权限会提示401:
设置获取token的时候 [AllowAnonymous],无需验证:
设置测试方法:需要System的权限才能访问:
上面我们是用的Admin的权限,所以会提示403错误
新增解析Token的方法:
1 /// <summary> 2 /// 解析Token 3 /// </summary> 4 /// <returns></returns> 5 [HttpGet] 6 [Authorize] 7 public IActionResult ParseToken() 8 { 9 //需要截取Bearer 10 var tokenHeader = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", ""); 11 var user = JwtHelper.SerializeJwt(tokenHeader); 12 return Ok(user); 13 14 }
解析出来的role是Admin。
标签:WebAPI,Claim,string,AppSettings,JWT,var,new,权限,public From: https://www.cnblogs.com/leon1128/p/18280526