标签:秘钥 obj 验证 base64编码 用户认证 ash 服务器部署 var 有助于
JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
下列场景中使用JSON Web Token是很有用的:
JSON Web Token由三部分组成,它们之间用圆点(.)连接。这三部分分别是:
因此,一个典型的JWT看起来是这个样子的:
xxxxx.yyyyy.zzzzz
接下来,具体看一下每一部分:
header典型的由两部分组成:token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)。
例如:
然后,用Base64对这个JSON编码就得到JWT的第一部分
JWT的第二部分是payload,它包含声明(要求)。声明是关于实体(通常是用户)和其他数据的声明。声明有三种类型: registered, public 和 private。
下面是一个例子:
对payload进行Base64编码就得到JWT的第二部分
注意,不要在JWT的payload或header中放置敏感信息,除非它们是加密的。
为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。
例如:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。
看一张官网的图就明白了:
在认证的时候,当用户用他们的凭证成功登录以后,一个JSON Web Token将会被返回。此后,token就是用户凭证了,你必须非常小心以防止出现安全问题。一般而言,你保存令牌的时候不应该超过你所需要它的时间。
无论何时用户想要访问受保护的路由或者资源的时候,用户代理(通常是浏览器)都应该带上JWT,典型的,通常放在Authorization header中,用Bearer schema。
header应该看起来是这样的:
Authorization: Bearer <token>
服务器上的受保护的路由将会检查Authorization header中的JWT是否有效,如果有效,则用户可以访问受保护的资源。如果JWT包含足够多的必需的数据,那么就可以减少对某些操作的数据库查询的需要,尽管可能并不总是如此。
如果token是在授权头(Authorization header)中发送的,那么跨源资源共享(CORS)将不会成为问题,因为它不使用cookie。
下面这张图显示了如何获取JWT以及使用它来访问APIs或者资源:
在讨论基于Token的身份认证是如何工作的以及它的好处之前,我们先来看一下以前我们是怎么做的:
HTTP协议是无状态的,也就是说,如果我们已经认证了一个用户,那么他下一次请求的时候,服务器不知道我是谁,我们必须再次认证
传统的做法是将已经认证过的用户信息存储在服务器上,比如Session。用户下次请求的时候带着Session ID,然后服务器以此检查用户是否认证过。
这种基于服务器的身份认证方式存在一些问题:
相同点是,它们都是存储用户信息;然而,Session是在服务器端的,而JWT是在客户端的。
Session方式存储用户信息的最大问题在于要占用大量服务器内存,增加服务器的开销。
而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。
Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。
基于Token的身份认证是无状态的,服务器或者Session中不会存储任何用户信息。
没有会话信息意味着应用程序可以根据需要扩展和添加更多的机器,而不必担心用户登录的位置。
虽然这一实现可能会有所不同,但其主要流程如下:
注意:
还有一点,token在一段时间以后会过期,这个时候用户需要重新登录。这有助于我们保持安全。还有一个概念叫token撤销,它允许我们根据相同的授权许可使特定的token甚至一组token无效。
(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
(2)JWT 不加密的情况下,不能将秘密数据写入 JWT。
(3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
(5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
代码实现
JWT的结构由三个部分组成
JWT = Base64(header) + Base64(payload) + HMAC SHA256(Base64(header) + Base64(payload))
注意:JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
这个 JSON 对象也要使用 Base64URL 算法转成字符串。
public static class Base64Url { /// <summary> /// Base64加密 /// </summary> /// <param name="arg"></param> /// <returns></returns> public static string Encode(byte[] arg) { if (arg == null) { throw new ArgumentNullException("arg"); } var s = Convert.ToBase64String(arg); return s .Replace("=", "") .Replace("/", "_") .Replace("+", "-"); } /// <summary> /// Base64加密 /// </summary> /// <param name="arg"></param> /// <returns></returns> public static string Encode(string arg) { if (arg == null) { throw new ArgumentNullException("arg"); } var plainTextBytes = Encoding.UTF8.GetBytes(arg); var s = Convert.ToBase64String(plainTextBytes); return s .Replace("=", "") .Replace("/", "_") .Replace("+", "-"); } private static string ToBase64(string arg) { if (arg == null) { throw new ArgumentNullException("arg"); } var s = arg .PadRight(arg.Length + (4 - arg.Length % 4) % 4, ‘=‘) .Replace("_", "/") .Replace("-", "+"); return s; } /// <summary> /// Base64解码 /// </summary> /// <param name="arg"></param> /// <returns></returns> public static string Decode(string arg) { var decrypted = ToBase64(arg); byte[] bytes = Convert.FromBase64String(decrypted); return Encoding.UTF8.GetString(bytes); } }
HMAC SHA256算法
public static string ToHmacSHA256Url(string message, string secret) { secret = secret ?? ""; var encoding = new System.Text.UTF8Encoding(); byte[] keyByte = encoding.GetBytes(secret); byte[] messageBytes = encoding.GetBytes(message); using (var hmacsha256 = new HMACSHA256(keyByte)) { byte[] hashmessage = hmacsha256.ComputeHash(messageBytes); return Convert.ToBase64String(hashmessage) .Replace("=", "") .Replace("/", "_") .Replace("+", "-"); } }
加密算法枚举
public enum JwtHashAlgorithm { HS256 = 0, HS384 = 1, HS512 = 2 }
JWT(JSON Web Token) 代码并不是很完善,可以自行修正错误。
public class JsonWebToken { /// <summary> /// JWT编码(JSON Web Token) /// </summary> /// <param name="payload">Json数据</param> /// <param name="key">密钥</param> /// <param name="algorithm">加密方式</param> /// <returns></returns> public static string Encode(object payload, string key, JwtHashAlgorithm algorithm) { string strHeaders = HeadersJWT(algorithm); string jsonPayload = JsonConvert.SerializeObject(payload, Formatting.Indented); string strPayload = Base64Url.Encode(jsonPayload); string strSignature = HmacSHA256.ToHmacSHA256Url(strHeaders + "." + strPayload, key); string strJWT = strHeaders + "." + strPayload + "." + strSignature; return strJWT; } /// <summary> /// JWT编码(JSON Web Token) /// </summary> /// <param name="extraHeaders">头文件</param> /// <param name="payload">Json数据</param> /// <param name="key">密钥</param> /// <param name="algorithm">加密方式</param> /// <returns></returns> public static string Encode(IDictionary<string, object> extraHeaders, object payload, string key, JwtHashAlgorithm algorithm) { string jsonHeaders = JsonConvert.SerializeObject(extraHeaders, Formatting.Indented); string strHeaders = Base64Url.Encode(jsonHeaders); string jsonPayload = JsonConvert.SerializeObject(payload, Formatting.Indented); string strPayload = Base64Url.Encode(jsonPayload); string strSignature = HmacSHA256.ToHmacSHA256Url(strHeaders + "." + strPayload, key); string strJWT = strHeaders + "." + strPayload + "." + strSignature; return strJWT; } /// <summary> /// Header头部内容 /// </summary> /// <param name="algorithm"></param> /// <returns></returns> private static string HeadersJWT(JwtHashAlgorithm algorithm) { Dictionary<string, object> headersJWT = new Dictionary<string, object>(); headersJWT.Add("alg",algorithm.ToString()); headersJWT.Add("typ","JWT"); string jsonHeaders = JsonConvert.SerializeObject(headersJWT, Formatting.Indented); string strHeaders = Base64Url.Encode(jsonHeaders); return strHeaders; } /// <summary> /// JWT解码(JSON Web Token),并验证有效性 /// </summary> /// <param name="token">JWT Token令牌</param> /// <param name="key">密钥</param> /// <param name="verify"></param> /// <returns></returns> public static string Decode(string token, string key, bool verify = true) { string strHeaders; string strPayload; string strSignature; string jsonPayload = null; string[] strJWT = token.Split(‘.‘); if (strJWT.Length == 3) { strHeaders = strJWT[0]; strPayload = strJWT[1]; strSignature = strJWT[2]; string isSignature = HmacSHA256.ToHmacSHA256Url(strHeaders + "." + strPayload, key); if (strSignature == isSignature) { jsonPayload = Base64Url.Decode(strPayload); } else { jsonPayload = ""; } } return jsonPayload; } }
标签:秘钥 obj 验证 base64编码 用户认证 ash 服务器部署 var 有助于
原文地址:https://www.cnblogs.com/im17me/p/10310426.html