| 
					
				 | 
			
			
				@@ -0,0 +1,177 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using Microsoft.Extensions.Options; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using Microsoft.IdentityModel.Tokens; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using Newtonsoft.Json; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Collections.Generic; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.IdentityModel.Tokens.Jwt; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Linq; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Security.Claims; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Security.Cryptography; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Text; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Threading.Tasks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+namespace WebAPIBase.Utils.Jwt 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// Token生成类 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public class TokenHelper : ITokenHelper 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly IOptions<JWTConfig> _options; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public TokenHelper(IOptions<JWTConfig> options) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _options = options; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// 根据一个对象通过反射提供负载生成token 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <typeparam name="T"></typeparam> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="user"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <returns></returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public TnToken CreateToken<T>(T user) where T : class 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //携带的负载部分,类似一个键值对 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            List<Claim> claims = new List<Claim>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //这里我们用反射把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 CreateTokenString(claims); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// 根据键值对提供负载生成token 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="keyValuePairs"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <returns></returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public TnToken CreateToken(Dictionary<string, string> keyValuePairs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //携带的负载部分,类似一个键值对 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            List<Claim> claims = new List<Claim>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //这里我们通过键值对把数据提供给它 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            foreach (var item in keyValuePairs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                claims.Add(new Claim(item.Key, item.Value)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //创建token 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return CreateTokenString(claims); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// 生成token 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="claims">List的 Claim对象</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <returns></returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private TnToken CreateTokenString(List<Claim> 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 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// 验证身份 验证签名的有效性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="encodeJwt"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="validatePayLoad">自定义各类验证; 是否包含那种申明,或者申明的值, </param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public bool ValiToken(string encodeJwt, Func<Dictionary<string, string>, bool> validatePayLoad = null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var success = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var jwtArr = encodeJwt.Split('.'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (jwtArr.Length < 3)//数据格式都不对直接pass 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var header = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[0])); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(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; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// 时间转换 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="date"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <returns></returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private long ToUnixEpochDate(DateTime date) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// 校验token状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="encodeJwt"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="validatePayLoad"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="action"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <returns></returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public TokenType ValiTokenState(string encodeJwt, Func<Dictionary<string, string>, bool> validatePayLoad, Action<Dictionary<string, string>> action) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var jwtArr = encodeJwt.Split('.'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (jwtArr.Length < 3)//数据格式都不对直接pass 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return TokenType.Fail; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var header = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[0])); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(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; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |