天天看點

JWT 幫助類 JWTHelper

JWTPlayloadInfo.cs 代碼如下:

/// <summary>
    /// JWT載荷實體
    /// </summary>
    public sealed class JWTPlayloadInfo
    {
        /// <summary>
        /// jwt簽發者
        /// </summary>
        public string iss { get; set; } = "Berry.Service";
        /// <summary>
        /// jwt所面向的使用者 UserId
        /// </summary>
        public string sub { get; set; } = "";
        /// <summary>
        /// 接收jwt的一方 
        /// </summary>
        public string aud { get; set; } = "";
        /// <summary>
        /// jwt的簽發時間
        /// </summary>
        public string iat { get; set; } = Utils.FormatDate(DateTime.Now, "1");
        /// <summary>
        /// jwt的過期時間,這個過期時間必須要大于簽發時間.預設60分鐘
        /// </summary>
        public string exp { get; set; }
        public TimeSpan daySpan { get; set; }
        /// <summary>
        /// 定義在什麼時間之前,該jwt都是不可用的.
        /// </summary>
        public int nbf { get; set; }
        public string ip { get; set; }
        /// <summary>
        /// jwt的唯一身份辨別,主要用來作為一次性token,進而回避重播攻擊。
        /// </summary>
        public string jti { get; set; } = Utils.GetGUID().ToString();
        /// <summary>
        /// 使用者ID。自定義字段
        /// </summary>
        public string userid { get; set; }
        /// <summary>
        /// 擴充字段。自定義字段
        /// </summary>
        public string extend { get; set; }
        /// <summary>
        /// 自定義對象
        /// </summary>
        public object data { get; set; }
        public string token { get; set; }
    }           

JWTHelper.cs 代碼如下:

using Currency.Redis;
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Currency.Common
{
    /// <summary>
    /// JWT操作幫助類
    /// </summary>
    public sealed class JWTHelper
    {
        /// <summary>
        /// 簽發Token
        /// </summary>
        /// <param name="playload">載荷</param>
        /// <returns></returns>
        public static string GetToken(JWTPlayloadInfo playload)
        {
            
            string token = String.Empty;
            IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
            IJsonSerializer serializer = new JsonNetSerializer();
            IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
            IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
            //設定過期時間
            DateTime time = DateTime.Now.Add(playload.daySpan);
            if (!string.IsNullOrEmpty(playload.iat))
            {
                var iat = DateTime.Now;
                try
                {
                    iat = DateTime.Parse(playload.iat);
                }
                catch (Exception)
                {
                    iat = DateTime.Now;
                }
                time = iat.Add(playload.daySpan);
            }
            playload.exp = Utils.GetTimeStamp(time);
            //擷取私鑰
            string secret = GetSecret();
            if (!string.IsNullOrEmpty(playload.sub))
            {
                token = encoder.Encode(playload, secret);
            }


            return token;
        }
       

        /// <summary>
        /// Token校驗
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public static JWTPlayloadInfo CheckToken(string token)
        {
            try
            {
                if (string.IsNullOrEmpty(token)) return null;

                IJsonSerializer serializer = new JsonNetSerializer();
                IDateTimeProvider provider = new UtcDateTimeProvider();
                IJwtValidator validator = new JwtValidator(serializer, provider);

                IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
                IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);

                //擷取私鑰
                string secret = GetSecret();
                JWTPlayloadInfo playloadInfo = decoder.DecodeToObject<JWTPlayloadInfo>(token, secret, true);
                if (playloadInfo != null)
                {
                    if (!string.IsNullOrEmpty(playloadInfo.sub))
                    {
                        var cacheToken = RedisHelper.StringGet($"user:login:{playloadInfo.sub}:{playloadInfo.jti}");
                        return Check(playloadInfo, cacheToken, token) ? playloadInfo : null;
                    }
                }
            }
            catch (Exception)
            {
                return null;
            }
            return null;
        }
       private static bool Check(JWTPlayloadInfo info, string cacheToken, string token)
        {
            if (string.IsNullOrEmpty(cacheToken)) return false;
            if (string.IsNullOrEmpty(token)) return false;
            if (!cacheToken.Equals(token)) return false;

            //Token過期
            DateTime exp = Utils.GetTime(info.exp);
            if (DateTime.Now > exp)
            {
                if (!string.IsNullOrEmpty(info.sub))
                {
                    RedisHelper.KeyDelete($"user:login:{info.sub}:{info.jti}");
                }
                return false;
            }
            return true;
        }
        /// <summary>
        /// 擷取私鑰
        /// </summary>
        /// <returns></returns>
        private static string GetSecret()
        {
            //TODO 從檔案中去讀真正的私鑰
            return "eyJpc3MiOiJCZXJyeS5TZXJ2aWNlIiwic3ViIjoiMTgyODQ1OTQ2MTkiLCJhdWQiOiJndWVzdCIsImlhdCI6IjE1MzEzODE5OTgiLCJleHAiOiIxNTMxMzg5MTk4IiwibmJmIjowLCJqdGkiOiI1YzdmN2ZhM2E4ODVlODExYTEzNTQ4ZDIyNGMwMWQwNSIsInVzZXJpZCI6bnVsbCwiZXh0ZW5kIjpudWxsfQ";
        }
    }

}
           

其中用到了 RedisHelper,請參考另一篇文章 https://blog.csdn.net/u013608482/article/details/88397789

繼續閱讀