JWT(JSON Web Tokens)操做幫助類

載荷實體:緩存

/// <summary>
    /// JWT載荷實體
    /// </summary>
    public sealed class JWTPlayloadInfo
    {
        /// <summary>
        /// jwt簽發者
        /// </summary>
        public string iss { get; set; } = "Berry.Service";
        /// <summary>
        /// jwt所面向的用戶
        /// </summary>
        public string sub { get; set; } = "ALL";
        /// <summary>
        /// 接收jwt的一方
        /// </summary>
        public string aud { get; set; } = "guest";
        /// <summary>
        /// jwt的簽發時間
        /// </summary>
        public string iat { get; set; } = DateTimeHelper.GetTimeStamp(DateTime.Now).ToString();
        /// <summary>
        /// jwt的過時時間,這個過時時間必需要大於簽發時間.默認60分鐘
        /// </summary>
        public string exp { get; set; }
        /// <summary>
        /// 定義在什麼時間以前,該jwt都是不可用的.
        /// </summary>
        public int nbf { get; set; }
        /// <summary>
        /// jwt的惟一身份標識,主要用來做爲一次性token,從而回避重放攻擊。
        /// </summary>
        public string jti { get; set; } = CommonHelper.GetGuid();
        /// <summary>
        /// 用戶ID。自定義字段
        /// </summary>
        public string userid { get; set; }
        /// <summary>
        /// 擴展字段。自定義字段
        /// </summary>
        public string extend { get; set; }
    }

JWTHelper.cs:ide

/// <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.AddMinutes(120);
            playload.exp = DateTimeHelper.GetTimeStamp(time).ToString();
            Dictionary<string, object> dict = playload.Object2Dictionary();
            //獲取私鑰
            string secret = GetSecret();
            //將Token保存在緩存中
            if (!string.IsNullOrEmpty(playload.aud) && playload.aud.Equals("guest"))
            {
                //計算公用Token
                token = CacheFactory.GetCacheInstance().GetCache("JWT_TokenCacheKey:Guest", () =>
                {
                    return encoder.Encode(dict, secret);
                }, time);
            }
            else
            {
                //計算Token
                token = CacheFactory.GetCacheInstance().GetCache($"JWT_TokenCacheKey:{playload.aud}", () =>
                {
                    return encoder.Encode(dict, secret);
                }, time);
            }
            return token;
        }

        /// <summary>
        /// Token校驗
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public static JWTPlayloadInfo CheckToken(string token)
        {
            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.aud) && playloadInfo.aud.Equals("guest"))
                {
                    string cacheToken = CacheFactory.GetCacheInstance().GetCache<string>("JWT_TokenCacheKey:Guest");

                    return Check(playloadInfo, cacheToken, token) ? playloadInfo : null;
                }
                else
                {
                    string cacheToken = CacheFactory.GetCacheInstance().GetCache<string>($"JWT_TokenCacheKey:{playloadInfo.aud}");
                    return Check(playloadInfo, cacheToken, token) ? playloadInfo : 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 = DateTimeHelper.GetDateTime(info.exp);
            if (DateTime.Now > exp)
            {
                if (!string.IsNullOrEmpty(info.aud) && info.aud.Equals("guest"))
                {
                    CacheFactory.GetCacheInstance().RemoveCache("JWT_TokenCacheKey:Guest");
                }
                else
                {
                    CacheFactory.GetCacheInstance().RemoveCache($"JWT_TokenCacheKey:{info.aud}");
                }
                return false;
            }
            return true;
        }

        /// <summary>
        /// 獲取私鑰
        /// </summary>
        /// <returns></returns>
        private static string GetSecret()
        {
            //TODO 從文件中去讀真正的私鑰
            return "eyJpc3MiOiJCZXJyeS5TZXJ2aWNlIiwic3ViIjoiMTgyODQ1OTQ2MTkiLCJhdWQiOiJndWVzdCIsImlhdCI6IjE1MzEzODE5OTgiLCJleHAiOiIxNTMxMzg5MTk4IiwibmJmIjowLCJqdGkiOiI1YzdmN2ZhM2E4ODVlODExYTEzNTQ4ZDIyNGMwMWQwNSIsInVzZXJpZCI6bnVsbCwiZXh0ZW5kIjpudWxsfQ";
        }
    }

自定義忽略驗證特性:ui

/// <summary>
    /// 忽略驗證
    /// </summary>
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    public class IgnoreTokenAttribute : Attribute
    {
        public bool Ignore { get; set; }
        /// <summary>
        /// 忽略驗證.默認忽略
        /// </summary>
        /// <param name="ignore"></param>
        public IgnoreTokenAttribute(bool ignore = true)
        {
            this.Ignore = ignore;
        }
    }

自定義Action攔截器,處理驗證邏輯:this

public class CustomActionFilterAttribute : ActionFilterAttribute
    {
        /// <summary>在調用操做方法以前發生。</summary>
        /// <param name="actionContext">操做上下文。</param>
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            string isInterfaceSignature = ConfigHelper.GetValue("IsInterfaceSignature");
            if (isInterfaceSignature.ToLower() == "false") return;

            BaseJsonResult<string> resultMsg = null;
            //受權碼
            string accessToken = string.Empty;
            //操做上下文請求信息
            HttpRequestMessage request = actionContext.Request;
            //數字簽名數據
            if (request.Headers.Contains("Authorization"))
            {
                accessToken = HttpUtility.UrlDecode(request.Headers.GetValues("Authorization").FirstOrDefault());
            }

            //接受客戶端預請求
            if (actionContext.Request.Method == HttpMethod.Options)
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Accepted);
                return;
            }

            //忽略不須要受權的方法
            var attributes = actionContext.ActionDescriptor.GetCustomAttributes<IgnoreTokenAttribute>();
            if (attributes.Count > 0 && attributes[0].Ignore) return;

            //判斷請求頭是否包含如下參數
            if (string.IsNullOrEmpty(accessToken))
            {
                resultMsg = new BaseJsonResult<string>
                {
                    Status = (int)JsonObjectStatus.ParameterError,
                    Message = JsonObjectStatus.ParameterError.GetEnumDescription()
                };
                actionContext.Response = resultMsg.ToHttpResponseMessage();
                return;
            }

            //校驗Token是否有效
            JWTPlayloadInfo playload = JWTHelper.CheckToken(accessToken);
            if (playload == null)
            {
                resultMsg = new BaseJsonResult<string>
                {
                    Status = (int)JsonObjectStatus.TokenInvalid,
                    Message = JsonObjectStatus.TokenInvalid.GetEnumDescription()
                };
                actionContext.Response = resultMsg.ToHttpResponseMessage();
                return;
            }
            else
            {
                //校驗當前用戶是否可以操做某些特定方法(好比更新用戶信息)
                if (!attributes[0].Ignore)
                {
                    if (!string.IsNullOrEmpty(playload.aud) && playload.aud.Equals("guest"))
                    {
                        resultMsg = new BaseJsonResult<string>
                        {
                            Status = (int)JsonObjectStatus.Unauthorized,
                            Message = JsonObjectStatus.Unauthorized.GetEnumDescription()
                        };
                        actionContext.Response = resultMsg.ToHttpResponseMessage();
                        return;
                    }
                }
            }

            base.OnActionExecuting(actionContext);
        }
    }

在WebApiConfig.cs中註冊:url

config.Filters.Add(new CustomActionFilterAttribute());

新增獲取Token控制器,添加獲取Token方法:spa

/// <summary>
        /// 獲取受權Token
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        [HttpPost]
        [IgnoreToken(true)]
        public HttpResponseMessage GetJWTToken(GetTokenArgEntity arg)
        {
            BaseJsonResult<string> resultMsg = this.GetBaseJsonResult<string>();

            Logger(this.GetType(), "獲取受權Token-GetJWTToken", () =>
            {
                if (!string.IsNullOrEmpty(arg.t))
                {
                    //TODO 根據UserID校驗用戶是否存在
                    if (true)
                    {
                        JWTPlayloadInfo playload = new JWTPlayloadInfo
                        {
                            iss = "Berry.Service",
                            sub = arg.Account,
                            aud = arg.UserId
                        };
                        string token = JWTHelper.GetToken(playload);

                        resultMsg = this.GetBaseJsonResult<string>(token, JsonObjectStatus.Success);
                    }
                    else
                    {
                        resultMsg = this.GetBaseJsonResult<string>(JsonObjectStatus.UserNotExist);
                    }
                }
                else
                {
                    resultMsg = this.GetBaseJsonResult<string>(JsonObjectStatus.Fail, ",請求參數有誤。");
                }
            }, e =>
            {
                resultMsg = this.GetBaseJsonResult<string>(JsonObjectStatus.Exception, ",異常信息:" + e.Message);
            });

            return resultMsg.ToHttpResponseMessage();
        }

獲取Token參數實體:code

/// <summary>
    /// 獲取Token參數
    /// </summary>
    public class GetTokenArgEntity : BaseParameterEntity
    {
        /// <summary>
        /// 用戶ID
        /// </summary>
        [Required(ErrorMessage = "UserId不能爲空")]
        public string UserId { get; set; }
        /// <summary>
        /// 賬號
        /// </summary>
        [Required(ErrorMessage = "Account不能爲空")]
        public string Account { get; set; }
    }
相關文章
相關標籤/搜索