载荷实体:

/// <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();
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 > && attributes[].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[].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)操作帮助类的更多相关文章

  1. Java分布式:JWT(JSON Web Tokens)

    Java分布式:JWT(JSON Web Tokens) 0.优势 Session方式存储用户状态占用大量服务器内存.一般而言,大型应用还需要借助一些KV数据库和一系列缓存机制来实现Session的存 ...

  2. ASP.NET Core 简单集成签发 JWT (JSON Web Tokens)

    什么是 JWT ? 从 https://jwt.io/ 可以了解到对 JWT 的描述:JSON Web Tokens are an open, industry standard RFC 7519 m ...

  3. JWT & JSON Web Tokens

    JSON Web Tokens https://jwt.io json web token example https://jwt.io/introduction/ https://medium.co ...

  4. jwt(JSON Web Tokens)的一道题目代码分析

    题目链接https://github.com/wonderkun/CTF_web/tree/5b08d23ba4086992cbb9f3f4da89a6bb1346b305/web300-6 参考链接 ...

  5. 单点登录-JWT(Json Web Tokens)

    来自:http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html 1.跨域认证 1.用户向服务器发送用户名和密码. 2.服务 ...

  6. [翻译]Introduction to JSON Web Tokens

    JWT: Json Web Tokens JWT是一种开放标准(RFC 7519),它定义了一种紧凑且独立的方式,用于将各方之间的信息安全地传输为JSON对象.因为它是经过数字签名的,所以该信息可以进 ...

  7. 服务安全-JWT(JSON Web Tokens):百科

    ylbtech-服务安全-JWT(JSON Web Tokens):百科 JSON Web Tokens是一种开放的行业标准 RFC 7519方法,用于在双方之间安全地表示索赔. JWT.IO允许您解 ...

  8. JSON Web Tokens(JWT)

    现在API越来越流行,如何安全保护这些API? JSON Web Tokens(JWT)能提供基于JSON格式的安全认证.它有以下特点: JWT是跨不同语言的,JWT可以在 .NET, Python, ...

  9. Java JWT: JSON Web Token

    Java JWT: JSON Web Token for Java and Android JJWT aims to be the easiest to use and understand libr ...

  10. Go实战--golang中使用JWT(JSON Web Token)

    http://blog.csdn.net/wangshubo1989/article/details/74529333 之前写过关于golang中如何使用cookie的博客: 实战–go中使用cook ...

随机推荐

  1. mysql数据库中锁机制的详细介绍

    悲观锁与乐观锁: 悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁.传统的关系型数据库里边就用到了很多这 ...

  2. 四十三.MongoDB副本集 MongoDB文档管理

    一.部署MongoDB副本集 1.1 启用副本集配置并指定集群名称 rs1 1.2 定义集群成员列表 部署好机器51,52,53:51上配置 bind_ip=192.168.4.51(要改) port ...

  3. 页面打开excel

    1. File => Stream / MemoryStream FileStream stream = new FileStream(path, FileMode.Open, FileAcce ...

  4. 爬虫(十五):scrapy中的settings详解

    Scrapy设定(settings)提供了定制Scrapy组件的方法.你可以控制包括核心(core),插件(extension),pipeline及spider组件.设定为代码提供了提取以key-va ...

  5. Unity的资源加载以及AssetBundle的一些坑

    https://www.cnblogs.com/sigmadruid/p/4040803.html AssetBundle加载完毕,进行其中Asset的初始化后,不能立即Unload().否则Asse ...

  6. 常见的时间字符串与timestamp之间的转换 时间戳

    这里说的字符串不是一般意义上的字符串,是指在读取日期类型的数据时,如果还没有及时解析字符串,它就还不是日期类型,那么此时的字符串该怎么与时间戳之间进行转换呢? ① 时间字符串转化成时间戳 将时间字符串 ...

  7. <frame>、<iframe>、<embed>、<object> 和 <applet>

    frame frame 必须在 frameset 里,而 frameset 又不能和 body 共存(就是一旦存在 frame,就不能存在 body 了,因此这个基本每人使用) 推荐阅读:https: ...

  8. 10月清北学堂培训 Day 5

    今天是廖俊豪老师的讲授~ T1 第一次想出正解 30 pts: k <= 10,枚举如何把数放到矩阵中,O ( k ! ): 100 pts: 对于矩阵的每一列,我们二分最小差异值,然后贪心去判 ...

  9. Tkinter 之pack布局

    一参数说明 参数 作用 anchor 控制组件在 pack 分配的空间中的位置"n", "ne", "e", "se", ...

  10. [ERR] 2006 - MySQL server has gone away如何解决

    解决方案: max_allowed_packet = 16M 改大点! 文章来源:外星人来地球 欢迎关注,有问题一起学习欢迎留言.评论