JWT(JSON Web Tokens)操作帮助类

Posted 大師兄丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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:

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

自定义忽略验证特性:

/// <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拦截器,处理验证逻辑:

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中注册:

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

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

/// <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参数实体:

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

 

以上是关于JWT(JSON Web Tokens)操作帮助类的主要内容,如果未能解决你的问题,请参考以下文章

JWT(JSON Web Tokens)

JSON Web Tokens(JWT)

JSON Web Tokens(JWT)

JWT(JSON Web Tokens)

jwt( JSON Web Tokens)

JSON Web Tokens介绍