第4章 认证机制:OAuth2.0、JWT、Session vs
说到接口认证,我最早是从 Session 开始入门的。那会儿做一个企业后台,session 一把梭,感觉挺爽。直到后来接手一个移动端项目,遇到了跨域、Session 无法共享的问题,才意识到——嗯,不同场景必须用不同的认证方案。
Session 与 :状态在谁手里?
Session 和 的核心区别,说白了就是「认证状态放哪」。Session 把状态存在服务端内存或 Redis 里,客户端只存一个 sessionId。 则把用户身份信息签名后直接发给客户端,服务端不保存会话。
我个人习惯:如果是纯服务端渲染的传统应用,Session 仍然是最简单的;一旦涉及多端、微服务或第三方接入,直接上 。
我曾经在一个电商系统中混用两种方案,结果发生 session 与 认证双重校验的 bug,排查了整整半天。从那以后我定了一个原则:一个项目只选一种主认证方式,不要混搭。
| 维度 | Session | |
|---|---|---|
| 存储位置 | 服务端(内存/Redis) | 客户端(localStorage/Cookie) |
| 扩展性 | 需要集中式 Session 存储 | 天然无状态,容易水平扩展 |
| 跨域支持 | 依赖 Cookie,跨域麻烦 | HTTP Header 携带,跨域友好 |
| 安全性 | 服务端可控,可主动销毁 | 令牌泄露后难立即失效 |
JWT:自包含的令牌
JWT(JSON Web )是目前最主流的 实现。它的体积小,可以携带用户基本信息,而且签名保证了完整性。为什么工程界都喜欢它?因为它能帮我们省掉一次数据库查询——服务端拿到 JWT 一验签名,就知道你是谁。
关键点:JWT 是“签名防篡改”而不是“加密防窥探”。如果你在 Payload 里放身份证号,那客户端一看 Base64 解码就全知道了。我见过有人把密码明文放 JWT 里,直接崩溃。
我在项目里遇到过两次 JWT 被重放的案例。客户端拿到 JWT 后,只要没过期,哪怕是别人偷用的也能正常请求。解决方案是搭配 jti(JWT ID)和黑名单机制,或者用短时效 + 刷新令牌的组合。我的建议:JWT 的过期时间不要超过 15 分钟,再配合 Refresh 来做续期。
// 一个标准的 JWT 结构示例
// Header
{
"alg": "HS256",
"typ": "JWT"
}
// Payload
{
"sub": "1234567890",
"name": "张三",
"iat": 1516239022,
"exp": 1516242622
}
// Signature: HMACSHA256(
// base64UrlEncode(header) + "." +
// base64UrlEncode(payload),
// secret
// )
OAuth2.0:授权框架
很多人把 OAuth2.0 和 JWT 混为一谈,其实它们是两个层面的东西。OAuth2.0 是一种授权协议,它解决的是「第三方应用如何安全地访问用户资源」。而 JWT 只是其中一种令牌格式,OAuth2.0 也可以使用其他令牌(比如不透明字符串)。
记得我做开放平台时,最头痛的是授权码流程(Authorization Code Flow)的 code 与 交换环节。有一次因为 redirect_uri 没有校验严格,被安全团队打回来整改。大家要记住:OAuth2.0 里 redirect_uri 必须完全匹配,不能写通配符。
警惕:Never 在客户端的 Implicit 模式中返回 access_(RFC 6749 已弃用这种模式)。现在官方只推荐授权码模式 + PKCE 扩展。
我个人在实践中坚持使用授权码模式(Authorization Code)并加上 PKCE。特别是移动端或单页应用,没有客户端密钥,PKCE 能防止授权码被截获后冒用。具体流程:
- 客户端生成一个 code_verifier 并计算 code_challenge
- 用户授权后服务端返回授权码
- 客户端用授权码 + code_verifier 换
- 服务端校验 code_verifier 是否匹配 code_challenge
认证方案选型决策图
下面这张图帮你理清 Session、、JWT 和 OAuth2.0 的关系。红色是核心概念,蓝色表示有状态方案,绿色表示无状态方案,紫色和橙色分别是 JWT 和 OAuth2.0 的位置。
如何选型?一张表搞定
你可能会问:这么多方案,我到底该用哪个?别急,我整理了一张实践对照表,按常见场景给出推荐:
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 内部管理系统(B/S) | Session + Cookie | 简单可控,服务端能主动踢人 |
| 移动端 App(原生) | JWT + Refresh | 无状态,便于多设备;短 防重放 |
| 单页前端 + API | JWT(短时效) + oauth2 PKCE | 无 cookie 跨域问题;PKCE 防授权码截获 |
| 第三方开放平台 | OAuth2.0 授权码模式 | 标准协议,第三方无需信任你的密码 |
| 微服务间通信 | JWT(内部 ) | 自包含,网关校验后直接传给下游 |
避坑指南:我曾经在一个微服务项目里,所有服务共用同一个 JWT Secret。后来一个业务服务被挖出漏洞,攻击者拿到 secret 后伪造了任意用户的 。血的教训——微服务之间应该使用独立的 JWT secret,或采用不对称签名(RS256)。
最后提一嘴,Session 不是万能的, 也不是银弹。理解每种方案背后的 trade-off,比盲目追逐新技术重要得多。你想想看,一个简单的工单系统用 OAuth2.0 套来套去,何必呢?