🧑💻 面试官:JWT 和 Session,你会怎么选?
🙋♂️ 我:Session 通常保存在服务端;JWT 可以验签,不必每次查询完整会话。
🧑💻 面试官:JWT 就更安全吗?放进 Cookie 以后,它是不是变成了 Session?
🙋♂️ 我:不是。Cookie 是携带机制,不能决定服务端怎样验证身份。
🧑💻 面试官:退出登录时删掉浏览器里的 JWT。别人手里的那份 Token,也会马上失效吗?
身份认证要分清「凭据形式、携带方式、验证与撤销」。保存在哪里,不能独自决定请求是否安全。
面试速答(60 秒版)
Session 方案通常在服务端保存会话状态,浏览器携带会话标识,服务端查到有效记录以后才接受身份。
JWT 是一种 Token 格式。常见签名 JWT 携带声明,服务端验证签名、过期时间、签发方和目标接收方等条件后才能接受。签名防篡改,不代表内容被加密。
Cookie 是浏览器保存并按规则携带数据的机制。它既能装 Session ID,也能装 JWT;JWT 也可以通过 Authorization 请求头发送。
选型需要考虑退出、封禁、权限变化和多服务验证。JWT 可以减少会话查询,但立即撤销往往需要额外状态。Session 便于集中管理,也需要可靠存储和过期机制。

知识点详解:一次请求怎样证明身份?
Session:浏览器给标识,服务端查记录
登录成功后,服务端生成难以猜测的 Session ID,把用户、有效期等信息保存在会话存储,再把 ID 交给浏览器。
后续请求带上 ID,服务端查询记录。存在且有效,才继续处理。浏览器通常不必保存完整身份资料,决定这个 ID 认不认的,是服务端记录。
集中删除会话、使某个用户的所有会话失效,都比较直接。但多实例共享、存储故障和扩容,也要设计。
OWASP 会话管理指南还讨论了标识强度、登录后更新标识和过期要求。不能只说“放进 Redis”就认为会话管理完成了。
JWT:不能只读到 userId 就放行
常见签名 JWT 有头部、载荷和签名。载荷可以包含用户标识与有效期。
服务端不能仅仅解码载荷。必须使用预期算法与可信密钥验签,再检查需要的声明和业务条件。
Token 如果签给服务 A,服务 B 不能只凭签名正确就当成自己的凭据;用户权限变化以后,也不能无条件相信旧角色。
RFC 8725给出了安全实践。这里讲常见签名形式;JWT 也有加密形式,但普通可解码载荷不能拿来保存秘密。
Cookie 不负责证明内容有效
| 这一层解决什么 | 例子 |
|---|---|
| 身份凭据的形式 | 随机会话标识、JWT |
| 请求怎样携带 | Cookie、Authorization |
| 服务端怎样接受 | 查会话、验签并检查声明与权限 |
所以,“JWT 对比 Cookie”不是同层比较。
Cookie 自动发送很方便,也需要考虑 CSRF。HttpOnly 限制脚本读取 Cookie,却不阻止浏览器按规则带它发请求。
把 Token 放进 localStorage,再手动加请求头,也不是天然安全。如果有 XSS,脚本可能读取 Token,或者直接操作账户。安全需要看整条链路。
退出登录,究竟使哪一份凭据失效?
删掉本地 JWT,只表示当前浏览器后续不再携带它。如果别人之前复制了一份,服务端又只检查签名和有效期,那份 Token 在过期前仍可能有效。
立即撤销可以结合会话记录、撤销列表或用户版本等机制。短期 Access Token 配合 Refresh Token 管理,也是一种选择,但已签发 Access Token 的失效时机仍需说明。
一旦每次请求都查撤销状态,就不能再说完全无状态。这不代表 JWT 没用,只是实际管理需要状态。
因此,普通网站需要集中退出和封禁时,Session 往往更直接;多个服务需要验证声明时,可以考虑 JWT。还要结合风险和现有基础设施,不凭新潮程度选。

面试官继续追问
Session 只能把用户粘在一台服务器上吗?
不一定。可以用共享会话存储,也可以在特定场景使用粘性会话。服务端有状态,不等于不能扩展。
改 JWT 中的用户 ID,签名还能通过吗?
正确验证的前提下,不能。若只解码、不验签,或者接受不可信算法,那是实现漏洞。
JWT 过期了,只要前端改时间就能续期吗?
不能。修改载荷会破坏签名。续期需要服务端规定的刷新流程,且刷新凭据也需要过期、撤销与安全管理。
面试速记卡
- Session:凭标识查服务端会话。
- JWT:验证签名与声明,不是只解码。
- Cookie:保存和携带机制,可以装不同凭据。
- 安全:签名不等于加密,HttpOnly 不防所有账户操作。
- 撤销:删本地副本,不等于别人手中的凭据失效。
