登录方式的演进(二):JWT,带着身份证去办事
上一篇我们讲了 Session + Cookie,那是 Web 登录的开山鼻祖。但当我们把系统拆成微服务之后,Session 的问题就暴露了——Session 存在服务端,服务一多就尴尬了。
一、Session 在微服务下的尴尬
想象一下:用户在订单服务登录了,Session 存在订单服务的内存里。然后他去调商品服务——商品服务说「你是谁?我不认识你。」
怎么办?共享 Session 呗。搞个 Redis 集群,所有服务都去查同一份 Session。
听起来没问题,但服务越来越多,每个服务都要依赖这个 Session 存储,耦合度拉满。Redis 一挂,全体服务瘫痪。
更别说移动端了——App 压根没有浏览器的 Cookie 机制,Session ID 要自己手动传,体验一言难尽。
二、JWT:把身份证揣自己兜里
JWT 的思路完全不同:别存了,把用户信息直接发给客户端,下次请求带回来就行。
就像你去政府办事,Session 是「你先去窗口登记,窗口给你发个号码牌,工作人员拿着号码牌去档案室查你是谁」;JWT 是「你把身份证揣兜里,到了直接亮证,工作人员看一眼就知道你是谁」。
不需要查档案室,信息就在证件上。
三、JWT 长什么样?
JWT 由三段组成,用点号拼接:
eyJhbGci....eyJzdWIi....SflKxwRJ...
对应的是:Header(头部) . Payload(载荷) . Signature(签名)
用比喻来说:
- Header 是信封,写着「这封信用了什么加密方式」,比如
alg: "HS256" - Payload 是信的内容,装着你的身份信息,比如
sub: "user123", role: "admin", exp: 1699000000 - Signature 是信封上的火漆印章,证明这封信没被篡改过
每一段都是 Base64 编码,不是加密。Payload 里的内容谁都能解码看,所以别往里面塞密码。
四、签名到底防的是什么?
有人可能会问:Payload 又不是加密的,别人改了怎么办?
这就是签名的作用。签名的生成逻辑大致是:
HMAC-SHA256(Header + "." + Payload, 密钥)
服务端收到 JWT 后,用同样的密钥和算法重新算一遍签名。如果和客户端传过来的签名不一致,说明内容被改过了,直接拒绝。
签名不保护隐私,保护的是完整性。
五、双 Token:Access Token + Refresh Token
JWT 有个特点:发出去就收不回来。所以通常不会给一个长有效期,而是搞两个 Token:
- Access Token:有效期短,比如 15 分钟,用来访问接口
- Refresh Token:有效期长,比如 7 天,专门用来换新的 Access Token
流程是这样的:
1 | 登录 → 拿到 Access Token + Refresh Token |
请求时长这样:
Authorization: Bearer eyJhbGci...
双 Token 的好处是:Access Token 泄露了,影响范围有限;Refresh Token 只在换 Token 时用,暴露面小。
六、JWT 的阿喀琉斯之踵
JWT 听起来很美好,但它有一个致命缺点:无法主动失效。
Session 的好处是存在服务端,想让用户下线,删掉 Session 就行。JWT 发出去以后,它就脱离你的控制了。
用户改了密码,想让所有设备重新登录?JWT 做不到,除非你等到它过期。Token 还活着,你拿它一点办法都没有。
有人说搞个黑名单,把要失效的 Token 存起来,每次请求都查一下黑名单——那你这不是又回到 Session 的老路了吗?
所以 JWT 和 Session 不是谁替代谁的关系,是不同场景下的不同选择。
七、什么时候用 JWT?
- 微服务架构,多个服务需要验证身份 → JWT,省去共享 Session 的麻烦
- 移动端 App → JWT,不依赖 Cookie 机制
- 需要灵活控制登录状态 → Session,随时能踢人
- 单体应用,用户量不大 → Session 就够了,别折腾
八、一句话总结
JWT 把身份信息从服务器搬到了客户端,换来了可扩展性,但失去了主动控制权。技术选型永远是权衡,不是银弹。
系列文章
- 登录方式的演进(一):Session + Cookie,Web 登录的开山鼻祖
- 登录方式的演进(二):JWT,带着身份证去办事
- 登录方式的演进(三):OAuth 2.0(下期)