zoukankan      html  css  js  c++  java
  • 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; }
        }
  • 相关阅读:
    LINQ 笔记
    关于:last-child的一点见解
    webpack 配置IP 和端口号
    echarts.制作中国地图,点击对应的省市链接到该省份的详细介绍
    关于offsetWidth innerWidth的使用
    关于mobiscroll插件的使用
    关于取url或者微信中参数的js
    上传图片
    使用默认图片替代某张图为空时的情况
    在数组中计算和的最大最小值
  • 原文地址:https://www.cnblogs.com/zhao-yi/p/9317835.html
Copyright © 2011-2022 走看看