JWT
为什么使用JWT?
通过 session
管理用户登录状态成本越来越高,因此慢慢发展成为 token
的方式做登录身份校验,然后通过 token
去取 redis
中的缓存的用户信息,随着之后jwt的出现,校验方式更加简单化,无需
通过 redis
缓存,而是 直接
根据 token
取出保存的用户信息,以及对 token
可用性校验,单点登录更为简单。
公钥和私钥
是通过一种 算法
得到的一个 密钥对
= 公钥
+ 私钥
公钥
:向外界公开私钥
:自己保留- 通过算法得到的
密钥对
能保证在世界范围内是唯一的。使用这个密钥对的时候,如果用 其中一个密钥加密
一段数据,必须用 另一个密钥解密
。比如用
公钥
加密数据就必须用私钥
解密,用私钥
加密必须用公钥
解密,否则解密将不会成功。
JWT 数据格式
Header
:对头部进行Base64Url
编码(可解码),头部包含两部分信息:
声明类型(JWT):"typ": "JWT",
加密算法(自定义):"alg": "HS256"
Payload
:对载荷(有效数据)进行Base64Url
编码(可解码),载荷(有效数据)的7个示例信息
(JSON形式):- iss (issuer):表示签发人 (举例如下):
"iss": "Oline JWT Builder"
- exp (expiration time):表示token过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
- iss (issuer):表示签发人 (举例如下):
Signature
:签名,是整个数据的认证信息。一般根据前两步的数据,再加上服务的的密钥secret
(密钥仅仅为保存在服务器中,并且不能向用户公开,即私钥
),通过Header
中配置的加密算法alg
生成。用于验证整个数据完整和可靠性。
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload),secret )
最终生成的JWT数据格式如下图:
注意:这里的数据通过 . 隔开成了三部分;另外,这里数据是不换行的,图片换行只是为了展示方便而已。
JWT交互流程
流程图:
因为JWT签发的 token
中已经包含了用户的身份信息,并且每次请求都会携带,这样服务的就无需保存用户信息,甚至无需去数据库查询,这样就完全符合了RESTful的无状态规范。
JWT 存在的问题
- 续签问题,传统的cookie+session的方案天然的支持续签,但是jwt由于
服务端
不保存用户状态,因此很难完美解决续签问题,如果引入redis,虽然可以解决问题,但是jwt也变得不伦不类了。 - 注销问题,由于
服务端
不再保存用户信息,所以一般可以通过修改secret来实现注销,服务端secret修改后,已经颁发的未过期的token就会认证失败,进而实现注销,不过毕竟没有传统的注销方便。 - 密码重置,密码重置后,原本的token依然可以访问系统,这时候也需要强制修改secret。
- 基于第2点和第3点,建议不同用户取不同secret。