Skip to content

03 · 认证与授权:Session / JWT / OAuth2 与权限模型 ​

速览卡 ​

项内容
一句话定位前端天天在处理 token,本篇讲清服务端的完整设计:你是谁(认证)与你能做什么(授权)
核心内容Session 与 JWT 的真实取舍、Token 存放位置、刷新机制、OAuth2/OIDC 适用场景、RBAC 与 ABAC
读完能回答我该用 Session 还是 JWT?token 放 localStorage 还是 Cookie?退出登录怎么做到真正失效?
相关板块02 · API 设计(401 与 403 的区别)| E01 · Python 基础 | 08 · 前端安全

一、先分清两件事 ​

概念英文回答的问题HTTP 表现
认证Authentication / AuthN你是谁401
授权Authorization / AuthZ你能做什么403

这两个词常被混用,但它们是两个独立的环节。 认证通过不代表有权限——登录成功只能说明"你是你",能不能看这份数据要看授权。


二、Session 与 JWT:真实的取舍 ​

维度Session(服务端状态)JWT(无状态)
状态存在哪服务端(Redis / DB)客户端(token 自带)
服务端要查吗每次查一次存储验签即可,不查库
立即失效✅ 删掉 session 就生效❌ 天然做不到(见下)
水平扩展需要共享存储(Redis)✅ 天然支持
跨域 / 多服务要处理 Cookie 域与共享✅ 天然适合
token 体积一个 ID,很小携带信息,较大
泄露后的影响删 session 即止在过期前一直有效

2.1 JWT 的"无法立即失效"是它最大的代价 ​

JWT 一旦签发,在过期前服务端无法单方面作废(因为不查库)。常见补救:

方案做法代价
短过期 + 刷新access token 5~15 分钟,靠 refresh token 续仍需 refresh token 的黑名单机制
黑名单 / 版本号验签后再查一次 Redis(是否作废)等于又变回有状态
换 Session干脆不用 JWT 存会话简单直接

💡 一句大实话:如果你需要"踢人下线""退出登录立刻生效""查看在线设备", 那你最终一定会引入服务端状态——此时 JWT 的"无状态优势"已经没了。

判断框架:

  • 需要即时失效 / 强管控 → Session
  • 服务间调用、短期授权、跨域 SSO → JWT
  • 拿不准 → Session,它更不容易出错

2.2 JWT 的结构(要知道里面没加密) ​

eyJhbGciOiJIUzI1NiIs...  .  eyJ1c2VySWQiOjEyM30...  .  HMAC签名
   Header(算法)              Payload(载荷)            Signature

⚠️ Payload 只是 Base64 编码,不是加密。任何人都能解出来看。 绝不能放密码、身份证、敏感业务数据。只放 userId、角色、过期时间这类非敏感信息。


三、Token 该放哪:前端最关心的问题 ​

存放位置XSS 风险CSRF 风险说明
localStorage❌ 高风险:XSS 可直接读取✅ 免疫(不自动发送)一旦有 XSS,token 就没了
Cookie(HttpOnly + Secure + SameSite)✅ JS 读不到⚠️ 需要防 CSRF推荐的常规做法
内存(变量)✅ 较好✅刷新页面即丢失,体验差

推荐组合:

access token  → HttpOnly Cookie(JS 读不到,防 XSS)
CSRF 防护     → SameSite=Lax/Strict + 同源校验 + 关键操作二次校验
refresh token → 更严格的 Cookie(路径限制 / 更长有效期 / 可轮换)

为什么不用 localStorage:XSS 无法完全避免(第三方脚本、依赖投毒、富文本), 而 localStorage 对 JS 完全开放。HttpOnly Cookie 是当前最稳妥的默认选择。


四、OAuth2 与 OIDC:什么时候才需要 ​

名词是什么你需要吗
OAuth2授权框架:让第三方应用拿到"有限权限"做第三方登录 / 开放平台时
OIDC在 OAuth2 之上加了一层身份认证需要"确认用户是谁"时
SSO单点登录:一次登录,多系统通用企业内部多系统

常见误解:"用微信登录"用的是 OAuth2 + OIDC,不是 OAuth2 单独。 OAuth2 只解决"授权",不解决"你是谁"——后者是 OIDC 的 id_token 提供的。

什么时候不需要 OAuth2:

  • 自己的系统、自己的用户 → 自己发 session/JWT 就够了
  • 只有一套前后端 → 不要为了"看起来专业"上 OAuth2

引入 OAuth2 的代价是真金白银的:授权服务器、client 管理、scope 设计、token 生命周期。 没有第三方参与就不要上。


五、权限模型:从简单到复杂 ​

模型表达适用
ACL用户 → 资源 → 权限(直接授予)少量资源、简单场景
RBAC用户 → 角色 → 权限绝大多数业务系统的默认选择
ABAC基于属性(部门/时间/金额)动态判断规则复杂、需要上下文

演进建议:从 RBAC 起步,遇到"同一个角色在不同部门权限不同"这类需求时, 再局部引入 ABAC。不要一上来就做通用权限引擎——那是投入产出比很低的坑。

一条容易忽略的原则:权限校验必须在服务端做,且在数据访问层再做一次。

❌ 只在前台隐藏按钮            → 直接调接口照样能访问
❌ 只在网关校验一次            → 内部调用、批量接口容易绕过
✅ 接口层校验 + 数据层过滤      → 越权查询从 SQL 层面就被拦住

尤其注意 IDOR(越权访问):/orders/123 改成 /orders/124 就能看别人的订单。 防御方式是查询时带上归属条件(where id = ? and user_id = ?),而不是先查后判。


六、自检清单 ​

  • [ ] 能区分 401 与 403,并知道各自该在什么情况返回
  • [ ] 说得出 JWT 的最大代价(无法立即失效)
  • [ ] 知道 JWT 的 Payload 不是加密
  • [ ] token 存放在 HttpOnly Cookie,且有 CSRF 防护
  • [ ] 退出登录能真正让会话失效
  • [ ] 密码用 bcrypt/argon2 等慢哈希存储(不是 MD5/SHA)
  • [ ] 权限校验在数据层也有兜底(防越权)
  • [ ] 知道自己不需要 OAuth2(除非有第三方参与)
  • [ ] 关键操作(改密码、付款)有二次验证

七、常见误区 ​

误区事实
"JWT 更安全"两者安全性取决于实现;JWT 的代价是无法即时失效
"JWT 里多存点信息方便"Payload 只是编码不加密,且会让 token 变大
"token 放 localStorage 最方便"XSS 一来就全没了;HttpOnly Cookie 更稳
"用了 HTTPS 就不用担心 token"HTTPS 防的是传输窃听,防不了 XSS 与本地泄露
"前端隐藏了按钮就等于没权限"接口必须独立校验,否则等于裸奔
"登录成功后就不用再校验权限了"每次数据访问都要带归属条件
"OAuth2 是登录协议"它是授权框架;身份认证靠 OIDC
"自己实现一套加密方案"用成熟库。密码学不要自己造

八、动手练习 ​

练习 A:设计一次"退出登录" ​

要求:用户点退出后,所有设备上的会话立即失效。 想一想:纯 JWT 能做到吗?做不到的话你会怎么改?

练习 B:找出越权漏洞 ​

python
@app.get("/orders/{order_id}")
def get_order(order_id: int, user=Depends(current_user)):
    return db.query(Order).filter(Order.id == order_id).first()

这里有安全漏洞吗?怎么修?

提示:换个 order_id 会发生什么。

练习 C:判断要不要上 OAuth2 ​

给三个场景(自家后台管理系统、支持微信登录的 App、要给合作方开放数据接口), 分别判断是否该引入 OAuth2,并说明理由。


相关文档 ​

本区 ​

其他域 ​