using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; namespace Wms_09.Tools { /// /// 配置token生成信息 /// public class JWTConfig { /// /// Token发布者 /// public string Issuer { get; set; } /// /// oken接受者 /// public string Audience { get; set; } /// /// 秘钥 /// public string IssuerSigningKey { get; set; } /// /// 过期时间 /// public int AccessTokenExpiresMinutes { get; set; } } /// /// 存放Token 跟过期时间的类 /// public class TnToken { /// /// token /// public string TokenStr { get; set; } /// /// 过期时间 /// public DateTime Expires { get; set; } } /// /// token工具类的接口,方便使用依赖注入,很简单提供两个常用的方法 /// public interface ITokenHelper { /// /// 根据一个对象通过反射提供负载生成token /// /// /// /// TnToken CreateToken(T user) where T : class; /// /// 根据键值对提供负载生成token /// /// /// TnToken CreateToken(Dictionary keyValuePairs); /// /// Token验证 /// /// token /// 自定义各类验证; 是否包含那种申明,或者申明的值 /// bool ValiToken(string encodeJwt, Func, bool> validatePayLoad = null); /// /// 带返回状态的Token验证 /// /// token /// 自定义各类验证; 是否包含那种申明,或者申明的值 /// /// TokenType ValiTokenState(string encodeJwt, Func, bool> validatePayLoad, Action> action); } /// /// Token生成类 /// public class TokenHelper : ITokenHelper { private readonly IOptions _options; public TokenHelper(IOptions options) { _options = options; } /// /// 根据一个对象通过反射提供负载生成token /// /// /// /// public TnToken CreateToken(T user) where T : class { //携带的负载部分,类似一个键值对 List claims = new List(); //这里我们用反射把model数据提供给它 foreach (var item in user.GetType().GetProperties()) { object obj = item.GetValue(user); string value = ""; if (obj != null) value = obj.ToString(); claims.Add(new Claim(item.Name, value)); } //创建token return CreateToken(claims); } /// /// 根据键值对提供负载生成token /// /// /// public TnToken CreateToken(Dictionary keyValuePairs) { //携带的负载部分,类似一个键值对 List claims = new List(); //这里我们通过键值对把数据提供给它 foreach (var item in keyValuePairs) { claims.Add(new Claim(item.Key, item.Value)); } //创建token return CreateTokenString(claims); } /// /// 生成token /// /// List的 Claim对象 /// private TnToken CreateTokenString(List claims) { var now = DateTime.Now; var expires = now.Add(TimeSpan.FromMinutes(_options.Value.AccessTokenExpiresMinutes)); var token = new JwtSecurityToken( issuer: _options.Value.Issuer,//Token发布者 audience: _options.Value.Audience,//Token接受者 claims: claims,//携带的负载 notBefore: now,//当前时间token生成时间 expires: expires,//过期时间 signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)), SecurityAlgorithms.HmacSha256)); return new TnToken { TokenStr = new JwtSecurityTokenHandler().WriteToken(token), Expires = expires }; } /// /// 验证身份 验证签名的有效性 /// /// /// 自定义各类验证; 是否包含那种申明,或者申明的值, public bool ValiToken(string encodeJwt, Func, bool> validatePayLoad = null) { var success = true; var jwtArr = encodeJwt.Split('.'); if (jwtArr.Length < 3)//数据格式都不对直接pass { return false; } var header = JsonConvert.DeserializeObject>(Base64UrlEncoder.Decode(jwtArr[0])); var payLoad = JsonConvert.DeserializeObject>(Base64UrlEncoder.Decode(jwtArr[1])); //配置文件中取出来的签名秘钥 var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(_options.Value.IssuerSigningKey)); //验证签名是否正确(把用户传递的签名部分取出来和服务器生成的签名匹配即可) success = success && string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1]))))); if (!success) { return success;//签名不正确直接返回 } //其次验证是否在有效期内(也应该必须) var now = ToUnixEpochDate(DateTime.UtcNow); success = success && (now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString())); //不需要自定义验证不传或者传递null即可 if (validatePayLoad == null) return true; //再其次 进行自定义的验证 success = success && validatePayLoad(payLoad); return success; } /// /// 时间转换 /// /// /// private long ToUnixEpochDate(DateTime date) { return (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds); } /// /// /// /// /// /// /// public TokenType ValiTokenState(string encodeJwt, Func, bool> validatePayLoad, Action> action) { var jwtArr = encodeJwt.Split('.'); if (jwtArr.Length < 3)//数据格式都不对直接pass { return TokenType.Fail; } var header = JsonConvert.DeserializeObject>(Base64UrlEncoder.Decode(jwtArr[0])); var payLoad = JsonConvert.DeserializeObject>(Base64UrlEncoder.Decode(jwtArr[1])); var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(_options.Value.IssuerSigningKey)); //验证签名是否正确(把用户传递的签名部分取出来和服务器生成的签名匹配即可) if (!string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1])))))) { return TokenType.Fail; } //其次验证是否在有效期内(必须验证) var now = ToUnixEpochDate(DateTime.UtcNow); if (!(now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString()))) { return TokenType.Expired; } //不需要自定义验证不传或者传递null即可 if (validatePayLoad == null) { action(payLoad); return TokenType.Ok; } //再其次 进行自定义的验证 if (!validatePayLoad(payLoad)) { return TokenType.Fail; } //可能需要获取jwt摘要里边的数据,封装一下方便使用 action(payLoad); return TokenType.Ok; } } public enum TokenType { Ok, Fail, Expired } }