载荷实体:
/// <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)操作帮助类
原文地址:https://www.cnblogs.com/zhao-yi/p/9317835.html