JWT中token的理解

今天我们来聊一聊关于JWT授权的事情 。
JWT:Json Web Token 。顾名思义,它是一种在Web中,使用Json来进行Token授权的方案 。
既然没有找好密码,token是如何解决信任问题的呢?
解决信任问题,只需要解决两个问题即可:
token是不是来自我信任的机构颁发
token中的信息是否被篡改
对于第一个问题而言,确认token确实是由被信任的第三方颁发的,一般都是通过加密算法来建立信任,颁发时使用密钥进行加密,如果能够对加密内容进行正常解密说明token来自信任方 。常用的加密算法分为:
对称可逆加密:使用同一个秘钥来加密解密,如果token能解密就能证明来源,秘钥不对外公开
非对称可逆加密:使用一组秘钥对(私钥加密+公钥解密),如果token能使用公钥进行解密就能证明来源,公钥与私钥之间互相不可推算
优缺点:
对称可逆加密效率高,速度快,但是由于对称可逆加密使用的是同一个秘钥,所以必须向解密的应用提供秘钥,相对而言不安全,所以一般只用于内部应用之间 。
非对称可逆加密速度相对慢一些,但是加密时通过私钥加密而解密时只需要提供公钥即可,所以用于对外提供加密机制更加安全可靠,所以多用于向第三方提供加密服务时使用 。
算法举例:
HS256HS256 (带有 SHA-256 的 HMAC 是一种对称算法, 双方之间仅共享一个 密钥 。由于使用相同的密钥生成签名和验证签名, 因此必须注意确保密钥不被泄密 。
2RS256RS256 (采用SHA-256 的 RSA 签名) 是一种非对称算法, 它使用公共/私钥对: 标识提供方采用私钥生成签名, JWT 的使用方获取公钥以验证签名 。由于公钥 (与私钥相比) 不需要保护, 因此大多数标识提供方使其易于使用方获取和使用 (通常通过一个元数据URL) 。
JWT格式说明
JWT令牌格式作用Header头    { "alg": "HS256", "typ": "JWT"}Payload有效载荷使用base64进行序列化,任何人都可以读到,所以不要包含敏感信息Signature签名防止抵赖-防止篡改,一旦头和有效载荷有内容被篡改,则生成签名部分必将与原内容不同
=HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
JWT如何解决信任问题的呢?
将签名部分使用秘钥进行解密,如果可以正常解开,说明令牌来自信任方颁发,将解密后的内容与JWT的头部和有效载荷的base64编码内容对比是否一致,如果一致,说明令牌未被篡改 。也就解决了token信任的第二个问题 。
算法实现:
下面是使用上述的两种加密算法生成的jwt
HS256算法实现
1 public string GetToken(UserInfoDTO userInfo) 2 { 3string secretKey = _configuration["SercetKey"]; 4var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)), SecurityAlgorithms.HmacSha256); 5 6var claims = new Claim[] { 7new Claim("id",userInfo.Id.ToString()), 8new Claim("age",userInfo.Age.ToString()), 9new Claim("name",userInfo.Name),10new Claim("mobile",userInfo.Mobile),11new Claim("email",userInfo.EMail),12new Claim("role",userInfo.Role),13};1415var token = new JwtSecurityToken(16issuer: _configuration["Issuer"], //发行人17audience: _configuration["Audience"], //受众人18claims: claims,19expires: DateTime.UtcNow.AddMinutes(2),//60分钟有效期20notBefore: DateTime.UtcNow.AddMinutes(1),//1分钟后有效21signingCredentials: signingCredentials);22string returnToken = new JwtSecurityTokenHandler().WriteToken(token);23return returnToken;24 }RSA256算法实现
1 public string GetToken(UserInfoDTO userInfo) 2 { 3string filepath = Directory.GetCurrentDirectory(); 4RSAParameters rSAParameter = default(RSAParameters); 5//没有生成过私钥文件,就创建,否则读取私钥 6if (!File.Exists(Path.Combine(filepath, "key.private.json"))) 7{ 8rSAParameter = GenerateAndSaveKey(filepath); 9}10else11{12rSAParameter = JsonConvert.DeserializeObject<RSAParameters>(File.ReadAllText(Path.Combine(filepath, "key.private.json")));13}1415var signingCredentials = new SigningCredentials(new RsaSecurityKey(rSAParameter), SecurityAlgorithms.RsaSha256);16var claims = new Claim[] {17new Claim("id",userInfo.Id.ToString()),18new Claim("age",userInfo.Age.ToString()),19new Claim("name",userInfo.Name),20new Claim("mobile",userInfo.Mobile),21new Claim("email",userInfo.EMail),22new Claim("role",userInfo.Role),23};2425var token = new JwtSecurityToken(26issuer: _configuration["Issuer"], //发行人27audience: _configuration["Audience"], //受众人28claims: claims,29expires: DateTime.UtcNow.AddMinutes(60),//60分钟有效期30notBefore: DateTime.UtcNow.AddMinutes(1),//1分钟后有效31signingCredentials: signingCredentials);32string returnToken = new JwtSecurityTokenHandler().WriteToken(token);33return returnToken;34 }

经验总结扩展阅读