本文不画图,不秀 code, 只讲一些概念上的东西, 防止大家误入歧途。
当然水平有限,有错误之处,请多指正,勿喷。
1 最重要的,不要考虑在服务器维护 JWT
Session是把用户认证信息放在服务器管理,JWT则是拿到了客户端,如果再在服务器维护JWT,不如直接用Session,若支持非Web客户端,手写个类Web Session的机制来管理客户端也不是难事,加上还有Redis加持。
理解这一点,能少走很多弯路。只要有在服务器维护JWT的念想,就直接干掉吧,比如:
2 鱼与熊掌不可兼得
2.1 Web Session 方案
优点
缺点
- 依赖 Cookie
- CSRF攻击(有解决方案)
- 扩展性问题(spring session + redis)
- 传说中的性能问题
2.2 JWT Session 方案
优点
- 不依赖 Cookie,支持各种客户端
- 自包含(自带防篡改的用户身份信息,比如Payload中存一个用户id或uuid)
- 服务器存取Session的资源得以释放
- JSON格式通用,支持各种语言
缺点
- 看Session优点中的几个问题
- 用户状态变化(删除,禁用,注销等)影响到业务而Token仍然有效时
3 几个应该知道的
- JWT是防篡改的,不能通过修改他的过期时间(exp) 来实现续期,一量修改,其实是生成了一个新的 Token
- 每次请求返回一个新的JWT token 虽然能“解决”续签问题,不说性能上的损耗,光这种做法就觉得不是正确的
4 使用 JWT,几个最佳实践
如果能容忍 JWT 的缺点,采用 JWT,以下是几个比较好的实践
使用 accessToken + refreshToken
- 认证后,返回 accessToken + refreshToken,并保存在本地, Web下推荐 HttpOnly cookie
- accessToken 使用 JWT 格式
- refreshToken 使用 UUID, 并维护在服务器端(使用得较少),不用 JWT (原因见第一大点)
- accessToken 失效时间应该设置较短,比如10分钟
- refreshToken 失效时间可以长一点,比如 7 天
- 请求时只用 accessToken
- accessToken 失效时,用 refreshToken 返回一个新的 accessToken(刷新 token)
- 刷新 token 时可对 refreshToken 做自动续期,提高用户体验
- 最好在 accessToken 在失效前主动 refreshToken
- 避免同时发送多个 refreshToken 请求
JWT 续签问题
-
客户端主动续签
客户端搞个线程定时主动检查Token过期时间,在过期前 (例如过期前1分钟) refresh一下Token
-
服务器端每次都续签
这个前面讲过,只是一种方法,但太不优雅
-
服务器端在Token过期前(例如过期前1分钟)续签
这个其实比较难掌控,假过期前1分内,客户端没有发请求,就续签不了,眼巴巴看着 session 过期,如果设置得过长,那么前面一个Token还会在相当长的时间内有效。而且假如一个 page 有10个请求同时过来,都达到刷新时间,那么会刷10次,最只有最后一次的起作用
所有续签的话,还是推荐客户端主动续签。
用户注销
用户点击注销,删除客户端 token。如果直接关客户端,只有等 accessToken过期
用户修改密码/禁用用户/删除用户
这几种情况在Session环境中可以更新/失效 session来达到安全要求,
但JWT不行,有效期内的accessToken会通过第一道验JWT的关卡,如果没有第二道验 user 的关卡,就直接通过去做业务逻辑了。
5 关于安全方面,几个认识和实践
- 使用 https保护你的应用
- sessionid 和 accessToken 泄露,造成的影响是一样,没有哪个更安全 (所以说 accessToken失效时间越短越安全)
- 不要在payload中不应该存放敏感信息,这部分客户端是可以解密的。
- secret_key 放在服务器端,不能泄露。
6 JWT 的使用场景
适合的
不适合的
6 BFF, 了解下?
- 不要设计成让所有类型的客户端调用相同的 API Servers
- 不同的Front 调用不同的Backend For Frontend Server
- 那么 WebServer用Session不香么
先写这么多,待补充。