JWT-生成、校验、解析Token(C#)

重要对象:

JwtSecurityToken:代表一个jwt token,可以直接用此对象生成token字符串,也可以使用token字符串创建此对象

SecurityToken:JwtSecurityToken的基类,包含基础数据

JwtSecurityTokenHandler:创建、校验token,返回ClaimsPrincipal
  CanReadToken():确定字符串是否是格式良好的Json Web令牌(JWT)
  ReadJwtToken(string token):token字符串转为JwtSecurityToken对象
  ValidateToken(string token、TokenValidationParameters parameter,out SecurityToken validatedToken):校验token,返回ClaimsIdentity,

  

方式1:

引用NuGet包:System.IdentityModel.Tokens.Jwt

static void Main(string[] args)
        {
            //引用System.IdentityModel.Tokens.Jwt
            DateTime utcNow = DateTime.UtcNow;
            string key = "f47b558d-7654-458c-99f2-13b190ef0199";
            SecurityKey securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key));

            var claims = new List<Claim>() {
                new Claim("ID","1"),
                new Claim("Name","fan")
            };
            JwtSecurityToken jwtToken = new JwtSecurityToken(
                issuer: "fan",
                audience: "audi~~!",
                claims: claims,
                notBefore: utcNow,
                expires: utcNow.AddYears(1),
                signingCredentials: new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256)
                );

            //生成token方式1
            string token1 = new JwtSecurityTokenHandler().WriteToken(jwtToken);
            //A Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor that contains details of contents of the token.

            var tokenDescriptor = new SecurityTokenDescriptor // 创建一个 Token 的原始对象
            {
                Issuer = "fan",
                Audience = "audi",
                Subject = new ClaimsIdentity(new[]
                       {
                            new Claim(ClaimTypes.Name, "")
                        }),
                Expires = DateTime.Now.AddMinutes(60),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key)), SecurityAlgorithms.HmacSha256)
            };
            //生成token方式2
            SecurityToken securityToken = new JwtSecurityTokenHandler().CreateToken(tokenDescriptor);
            var token2 = new JwtSecurityTokenHandler().WriteToken(securityToken);

            //校验token
            var validateParameter = new TokenValidationParameters()
            {
                ValidateLifetime = true,
                ValidateAudience = true,
                ValidateIssuer = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = "fan",
                ValidAudience = "audi~~!",
                IssuerSigningKey = securityKey,
            };
            //不校验,直接解析token
            //jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token1);
            try
            {
                //校验并解析token
                var claimsPrincipal = new JwtSecurityTokenHandler().ValidateToken(token1, validateParameter, out SecurityToken validatedToken);//validatedToken:解密后的对象
               var jwtPayload = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson(); //获取payload中的数据 
                
            }
            catch (SecurityTokenExpiredException)
            {
                //表示过期
            }
            catch (SecurityTokenException)
            {
                //表示token错误
            }
        }

方式2:

引用Nuget包:JWT 

       /// <summary>
        /// 创建token
        /// </summary>
        /// <returns></returns>
        public static string CreateJwtToken(IDictionary<string, object> payload, string secret, IDictionary<string, object> extraHeaders = null)
        {
            IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
            IJsonSerializer serializer = new JsonNetSerializer();
            IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
            IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
            var token = encoder.Encode(payload, secret);
            return token;
        }
        /// <summary>
        /// 校验解析token
        /// </summary>
        /// <returns></returns>
        public static string ValidateJwtToken(string token, string secret)
        {
            try
            {
                IJsonSerializer serializer = new JsonNetSerializer();
                IDateTimeProvider provider = new UtcDateTimeProvider();
                IJwtValidator validator = new JwtValidator(serializer, provider);
                IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
                IJwtAlgorithm alg = new HMACSHA256Algorithm();
                IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, alg);
                var json = decoder.Decode(token, secret, true);
                //校验通过,返回解密后的字符串
                return json;
            }
            catch (TokenExpiredException)
            {
                //表示过期
                return "expired";
            }
            catch (SignatureVerificationException)
            {
                //表示验证不通过
                return "invalid";
            }
            catch (Exception)
            {
                return "error";
            }
        }


//-------------客户端调用---------------
public static void Main(string[] args)
        {
            var sign = "123";
            var extraHeaders = new Dictionary<string, object>
                     {
                                          { "myName", "limaru" },
                    };
            //过期时间(可以不设置,下面表示签名后 10秒过期)
            double exp = (DateTime.UtcNow.AddSeconds(10) - new DateTime(1970, 1, 1)).TotalSeconds;
            var payload = new Dictionary<string, object>
                     {
                                         { "userId", "001" },
                         { "userAccount", "fan" },
                         { "exp",exp }
                                     };
            var token = CreateJwtToken(payload, sign, extraHeaders);
            var text = ValidateJwtToken(token, sign);
            Console.ReadKey();
        }

方式3:

手写jwt算法:

JWT组成

  样式:"xxxxxxxxxxxx.xxxxxxxxxxxxx.xxxxxxxxxxxxxxxx"由三部分组成.

(1).Header头部:{"alg":"HS256","typ":"JWT"}基本组成,也可以自己添加别的内容,然后对最后的内容进行Base64编码.

(2).Payload负载:iss、sub、aud、exp、nbf、iat、jti基本参数,也可以自己添加别的内容,然后对最后的内容进行Base64编码.

(3).Signature签名:将Base64后的Header和Payload通过.组合起来,然后利用Hmacsha256+密钥进行加密。

#region Base64编码
 2         /// <summary>
 3         /// Base64编码
 4         /// </summary>
 5         /// <param name="text">待编码的文本字符串</param>
 6         /// <returns>编码的文本字符串</returns>
 7         public string Base64UrlEncode(string text)
 8         {
 9             var plainTextBytes = Encoding.UTF8.GetBytes(text);
10             var base64 = Convert.ToBase64String(plainTextBytes).Replace('+', '-').Replace('/', '_').TrimEnd('=');
11             return base64;
12         }
13         #endregion
14 
15         #region Base64解码
16         /// <summary>
17         /// Base64解码
18         /// </summary>
19         /// <param name="base64UrlStr"></param>
20         /// <returns></returns>
21 
22         public string Base64UrlDecode(string base64UrlStr)
23         {
24             base64UrlStr = base64UrlStr.Replace('-', '+').Replace('_', '/');
25             switch (base64UrlStr.Length % 4)
26             {
27                 case 2:
28                     base64UrlStr += "==";
29                     break;
30                 case 3:
31                     base64UrlStr += "=";
32                     break;
33             }
34             var bytes = Convert.FromBase64String(base64UrlStr);
35             return Encoding.UTF8.GetString(bytes);
36         }
#endregion Base64编码和解码

/// <summary>
        /// 手写JWT算法
        /// </summary>
        public bool TestJwt1()
        {
            string secretKey = Configuration["SecretKey"];
            //1.加密
            //1.1 表头的处理
            string headerBase64Url = this.Base64UrlEncode("{"alg":"HS256","typ":"JWT"}");
            //1.2 PayLoad的处理
            var jwtPayLoad = new
            {
                expire = DateTime.Now.AddMinutes(15),
                userId = "00000000001",
                userAccount = "admin"
            };
            string payloadBase64Url = this.Base64UrlEncode(JsonConvert.SerializeObject(jwtPayLoad));
            //1.3 Sign的处理
            string sign = $"{headerBase64Url}.{payloadBase64Url}".HMACSHA256(secretKey);
            //1.4 最终的jwt字符串
            string jwtStr = $"{headerBase64Url}.{payloadBase64Url}.{sign}";

            //2.校验token是否正确
            bool result;   //True表示通过,False表示未通过
            //2.1. 获取token中的PayLoad中的值,并做过期校验
            JwtData myData = JsonConvert.DeserializeObject<JwtData>(this.Base64UrlDecode(jwtStr.Split('.')[1]));  //这一步已经获取到了payload中的值,并进行转换了
            var nowTime = DateTime.Now;
            if (nowTime > myData.expire)
            {
                //表示token过期,校验未通过
                result = false;
                return result;
            }
            else
            {
                //2.2 做准确性校验
                var items = jwtStr.Split('.');
                var oldSign = items[2];
                string newSign = $"{items[0]}.{items[1]}".HMACSHA256(secretKey);
                result = oldSign == newSign;  //true表示检验通过,false表示检验未通过
                return result;
            }
        }
View Code

 

参考:

https://www.cnblogs.com/ye-hcj/articles/8151385.html

https://www.cnblogs.com/yaopengfei/p/12162507.html

原文地址:https://www.cnblogs.com/fanfan-90/p/12911203.html