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;
            }
        }

參考:

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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM