出售域名 11365.com.cn
有需要请联系 16826375@qq.com
在手机上浏览
在手机上浏览

JWT=JSON Web Token

发布日期:2021-06-09

1、    JWT是什么
Json Web Token的简称,是一种安全可靠的身份认证机制。
JWT弥补了Session做为分布式身份认证方面的不足
官方说明:https://jwt.io/introduction

2、    JWT的优势
传统意义上的身份认证,是把认证信息存储到服务器端,比如存储到内存、数据库等。当客户端连接数量过大时,造成了服务端的巨大压力。
而JWT在验证之后是存储在客户端的,减轻了服务器端的压力!

3、    JWT的组成
JWT一般由三段构成,用.号分隔开,第一段是header,第二段是payload,第三段是signature,例如:
xxxxx.yyyyy.zzzzz

1)    Header
头部信息,标注了加密信息,如:
{
  "alg": "HS256",
  "typ": "JWT"
}

2)    Payload
主要附带信息,
iss : jwt签发者
sub:jwt所面向的用户
aud:接收jwt的一方
exp:jwt的过期时间,这个过期时间必须要大于签发时间
nbf:定义在什么时间之前,该jwt都是不可用的.
iat :jwt的签发时间
jti  :jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
如:
{
  "sub": "jsonlee",
  "exp": 1623208480
}

3)    Signature
签名,即HMACSHA256(base64URLCode(header) ”.” base64URLCode(payload), secret)

 

完整的例子

首先在Nuget中引入JWT和SinGooCMS.Utility两个包

using System;
using System.Collections.Generic;
using SinGooCMS.Utility;
using System.Security.Cryptography;
using JWT;
using JWT.Algorithms;
using JWT.Serializers;

namespace JWT_Test
{
    class Program
    {
        //密钥
        static string secret = "16826375@qq.com";

        static void Main(string[] args)
        {
            //原始的
            Console.WriteLine("原始的\r\n");
            var headerResult = GetHeaderEncode();
            Console.WriteLine("header:"   headerResult.Item1   " | header_encode:"   headerResult.Item2   "\r\n");
            var payloadResult = GetPayloadEncode();
            Console.WriteLine("payload:"   payloadResult.Item1   " | payload_encode:"   payloadResult.Item2   "\r\n");
            var signature = GetSignature();
            Console.WriteLine("signature:"   signature   "\r\n");

            //使用JWT工具
            var payload = new Dictionary<string, object>() {
                { "sub","jsonlee"},
                { "exp",1623208480}
            };

            IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
            IJsonSerializer serializer = new JsonNetSerializer();
            IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
            IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);

            //加密 身份验证成功后,服务器生成token,并发送到客户端
            var token = encoder.Encode(payload, secret);
            //FileUtils.CreateFileAsync("c:/jwt.txt", token).GetAwaiter().GetResult();
            Console.WriteLine("\r\n  使用JWT工具 \r\n");
            Console.WriteLine("token:" token  "\r\n");

            //解密,客户请求资源时,把token带上,在服务端进行解密
            var token2 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqc29ubGVlIiwiZXhwIjoxNjIzMjA4NDgwfQ.Y-m0knDfE7PsM9TYkwZsuF0A-Ze7kKwblU3MYtK2O24";
            IDateTimeProvider provider = new UtcDateTimeProvider();
            IJwtValidator validator = new JwtValidator(serializer, provider);
            IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
            var tokenOriginal = decoder.Decode(token2);
            Console.WriteLine("\r\n \r\n");
            Console.WriteLine("token original:"   tokenOriginal   "\r\n");
        }

        #region 原始的JWT分步解析 

        /*
        对照 https://jwt.io/#debugger 
        检测我们的数据是否正确
         */

        private static (string, string) GetHeaderEncode()
        {
            /*
             * base64编码 header头部信息
             {
                "typ": "JWT",
                "alg": "HS256"                
            }
             */
            var header = "{\"typ\":\"JWT\",\"alg\":\"HS256\"}";
            return (header, DEncryptUtils.Base64Encrypt(header).Replace(' ', '-').Replace('/', '_').Replace("=", ""));
        }

        private static (string, string) GetPayloadEncode()
        {
            /*
            iss:jwt签发者
            sub:jwt所面向的用户
            aud:接收jwt的一方
            exp:jwt的过期时间,这个过期时间必须要大于签发时间
            nbf:定义在什么时间之前,该jwt都是不可用的.
            iat:jwt的签发时间
            jti:jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
             */
            IDateTimeProvider provider = new UtcDateTimeProvider();
            var now = provider.GetNow();
            var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); // or use JwtValidator.UnixEpoch
            var secondsSinceEpoch = Math.Round((now - unixEpoch).TotalSeconds);
            //var payload = $"{{\"sub\":\"jsonlee\",\"exp\":{secondsSinceEpoch   100}}}";
            var payload = "{\"sub\":\"jsonlee\",\"exp\":1623208480}";

            return (payload, DEncryptUtils.Base64Encrypt(payload).Replace(' ', '-').Replace('/', '_').Replace("=", ""));
        }

        private static string GetSignature()
        {
            // header_encode "." payload_encode
            string info = GetHeaderEncode().Item2   "."   GetPayloadEncode().Item2;
            return SHA256Encrypt(info, secret);
        }

        #region SHA256加密
        /// <summary>
        /// HMAC SHA256 (Base64)
        /// </summary>
        /// <param name="message"></param>
        /// <param name="secret"></param>
        /// <returns></returns>
        public static string SHA256Encrypt(string message, string secret)
        {
            secret = secret ?? "";
            var encoding = new System.Text.ASCIIEncoding();
            byte[] keyByte = encoding.GetBytes(secret);
            byte[] messageBytes = encoding.GetBytes(message);
            using (var hmacsha256 = new HMACSHA256(keyByte))
            {
                byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                return Convert.ToBase64String(hashmessage).Replace(' ', '-').Replace('/', '_').Replace("=", "");
            }
        }
        #endregion

        #endregion
    }
}

运行后,得出的结果对比


与官网的测试对比