一、概述
虽然现在很多的开发框架会支持JWT的使用,但是对JWT还是没有一个详细的了解,有很多疑惑:
- JWT比之前的session或者token有什么好处?
- JWT的构成元素是什么?
- JWT从生成到使用的详细流程?
二、 JWT
2.1 JWT是什么?
JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
2.2 在什么场景使用JWT?
-
授权
授权是我们使用JWT最常见的场景;用户登录后,后端服务根据JWT规则生成token给到前端,前端之后的请求都会携带这个token访问后端接口,后端对这些请求校验token,保障token的有效性,进而确保是合法请求;JWT非常契合单点登录,因为JWT的后端认证不需要额外访问存储信息,只需要一个秘钥就可以自认证;
-
交换信息
由于JWT生成的token可以包含业务信息,而且这些业务信息是参与了签名的,所以保障了这些业务信息不被篡改,而且还有有效时间范围;
2.3 JWT生成规则
JWT整体的组成形式类似为: xxxx.yyyy.zzzz
JWT 本质上就是一组字串,通过(.
)切分成三个为 Base64 编码的部分:
-
Header : 描述 JWT 的元数据,定义了生成签名的算法以及
Token
的类型;
示例:{"typ":"JWT","alg":"HS256"}
-
Payload : 用来存放实际需要传递的数据;
示例:{"sub":"123456","exp":1713939930564,"userid":"28912"}
注意:由于Payload是明文传输和前端存储,所以不能存放隐私性信息
-
Signature(签名):服务器通过 Payload、Header 和一个密钥(Secret)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。
示例:HMACSHA256( base64UrlEncode({"typ":"JWT","alg":"HS256"}) + "." + base64UrlEncode({"sub":"123456","exp":1713939930564,"userid":"28912"}), "123456789qwer")
最终得出的token示例:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJzdWIiOiIxMjM0NTYiLCJleHAiOjE3MTM5Mzg4NTkzNDIsInVzZXJpZCI6IjI4OTEyIn0.
qFxI_m6XOYMdASi9nXpaOtr3p2SQCy8OOIktWhJBnCQ
至于其中的算法,可以按照JWT的严格算法来实现,也可以按照自己的算法来实现,只需要保证生成token
和验证token
时的算法一致即可;
2.4 JWT、session、redis存储的token对比
JWT | redis存储的token | 本地session | |
---|---|---|---|
服务端是否需要存储用户认证成功的信息 | 不需要 | 需要 | 需要 |
认证成功的用户信息存储在哪 | 客户端 | redis | 本地 |
生成的token是否可以跨域使用 | 可以 | 可以 | 不可以 |
上述表格对比了JWT
redis存储的token
本地session
三者的一些特性;
-
JWT由于包含了认证的用户信息,那么就不需要后端服务再额外保存这些认证信息,所以节省了后端的资源;
-
JWT由于自包含认证信息,所以可以不依赖后端服务,可以在不同的后端服务之间认证使用;所以非常契合单点登录的实现;
-
JWT默认使用请求头
Authorization
向后端传输,当然你也可以使用其他请求头,只需要前后端一致即可;Authorization: Bearer {JWTtoken}
-
JWT由于摆脱了传统的cookie传输,所以跨资源(CORS)不会成为问题,有助于防止CSRF攻击;
2.5 JWT认证流程
上图是JWT在单点登录的认证流程过程;
如果后端是微服务架构,那么
验证JWT是否合法
这个功能可以集成到API网关层,统一处理即可;