关键决策
这一页整理认证系统设计过程中遇到的关键决策点。每个决策都说明了问题、对比过的方案和最终选择理由。
决策 1:不透明 Token 还是 JWT
问题
用户登录后,后续请求用什么凭证证明身份?
方案对比
| 方案 | 撤销 | 跨服务验证 | 存储 | 典型场景 |
|---|---|---|---|---|
| 不透明 Token | 容易 | 需查服务端 | 数据库/缓存 | 单服务、需强撤销 |
| JWT | 困难 | 离线验证 | 无状态 | 分布式、跨服务传递 |
决策
高安全场景用短期 JWT + 服务端会话的组合:JWT 承担跨服务传递,会话记录承担撤销和审计。如果撤销需求特别强(如金融、账号风控),优先不透明 Token。
决策 2:Cookie 还是 Authorization Header
问题
浏览器端登录态放在哪里?
方案对比
- Cookie(HttpOnly + Secure + SameSite):降低 XSS 读取风险,但要处理 CSRF。
- Authorization Header(LocalStorage/内存):实现简单,适合 API 和移动端,但更容易被 XSS 窃取。
决策
浏览器端优先 HttpOnly Cookie,让脚本读不到 Token,把 XSS 风险挡在门外;CSRF 用 SameSite + 校验来源处理。移动端和纯 API 场景用 Authorization Header,重点防 XSS 和本地存储泄露。
决策 3:Access Token 与 Refresh Token 拆分
问题
单一 Token 要么有效期短(体验差),要么有效期长(风险大),如何平衡?
决策
拆成两个 Token:Access Token 短期有效(分钟到小时级),用于访问 API;Refresh Token 长期有效,用于换新。同时给 Refresh Token 做轮换(每次刷新换新值)、绑定设备和可撤销。这样 Access Token 泄露的风险窗口短,Refresh Token 泄露可以通过设备绑定和重放检测发现。
决策 4:会话过期策略
问题
会话多久过期?固定过期还是滑动过期?
方案对比
- 固定过期:登录后 7 天必须重新登录,安全但体验差。
- 滑动过期:持续活跃自动延长,体验好但风险窗口大。
决策
组合使用:短期 Access Token + 较长 Refresh Token + 最长会话生命周期。用户持续活跃时用 Refresh Token 续期,但设定一个绝对上限(如 30 天),超过就必须重新登录。既照顾体验,又控制风险。
决策 5:MFA 是否每次触发
问题
MFA 增强安全,但每次都触发会严重伤害用户体验。
决策
采用自适应 MFA:新设备、异地、高风险操作才触发;常用设备、低风险场景直接放行。通过 MFA 后给会话记录 assurance_level = high,在一定时间内敏感操作不再重复验证,超过有效期或风险变化后再要求重新验证。
决策 6:SSO 是否统一登出
问题
用户在认证中心退出后,业务系统本地会话是否也要失效?
方案对比
- 前端重定向通知:实现简单,但依赖浏览器跳转,不可靠。
- 后端通道通知:可靠,但要维护各系统回调。
- 缩短本地会话:降低残留风险,但体验略差。
决策
内部管理系统要求统一登出(后端通道为主),普通内容站点可以放宽。统一登出越彻底,实现越复杂,安全要求决定投入程度。
决策 7:第三方登录后账号怎么建
问题
用户用 GitHub/微信登录,本地系统如何绑定和创建账号?
决策
本地系统保留自己的用户 ID,外部平台的 openid 只作为 identity_binding 存储,不作为内部主键。第一次第三方登录时按策略自动建号或引导绑定;用户可解绑;第三方撤销授权后,本地会话按风险降级处理。这样用户换身份来源也不会丢失本地数据。
决策 8:密码哈希算法
问题
密码如何存储才安全?
决策
用带盐的慢哈希算法(bcrypt / scrypt / Argon2),数据库只保存 password_hash、算法版本和参数。绝不使用 MD5/SHA 等快速哈希(容易被 GPU 暴力破解),也绝不存储明文或可逆加密。算法升级时保留版本号,支持渐进式迁移。
