跳转到主要内容

你将构建什么

一个生产级的 Token 管理层——覆盖持久化存储选型、多用户隔离、并发刷新竞争、过期降级、主动撤销和安全存储,确保你的 SaaS 应用在 Token 轮换和服务重启后仍然正常工作。

Token 生命周期

核心原则

违反以下任何一条,都会导致用户静默掉线——没有错误提示,只有突然的「请重新登录」。
1. 刷新后必须持久化onTokenRefresh 回调是你保存新 Token 的唯一时机。错过它,旧 Refresh Token 已失效,新 Token 丢失,用户必须重新授权。 2. 禁止纯内存存储 — 服务重启 = 所有用户 Token 丢失 = 全体重新登录。Token 必须落盘(DB / Redis / 文件)。 3. 轮换必须原子化 — 每次 refreshToken() 调用后,旧的 Access Token 和 Refresh Token 同时失效。保存新 Token 和废弃旧 Token 必须在同一事务中完成。

Step 1: 选择存储策略

80% 的场景直接用 Contrib 的 DrizzleTokenStore 或 SQLAlchemyTokenStore 即可。只有特殊需求(Redis Session、自定义加密)才需要自行实现。

使用 Contrib 存储

使用 Redis 自定义存储

Step 2: 多用户 Token 管理

SaaS 应用通常为每个用户维护独立的 Token。核心模式:以 userId 为键,隔离读写

Step 3: 并发刷新竞争

问题:两个请求同时发现 Access Token 过期,都尝试刷新。第一个成功,第二个因 Refresh Token 已轮换而收到 invalid_grant 解决方案:用互斥锁保证同一用户同一时刻只有一个刷新操作。
Python 版本在获取锁后重新检查 Token 是否已被其他协程刷新(double-check pattern),避免重复刷新。TypeScript 版本通过共享同一个 Promise 实现相同效果。
对于多实例部署(多 Pod / 多进程),进程内的 Map / dict 锁不够。需要分布式锁:

Step 4: Token 过期降级

当 Refresh Token 也过期(90 天未使用)或被撤销时,SDK 抛出 AuthExpired。此时唯一的恢复路径是引导用户重新授权。
前端处理 auth_expired 响应:
前端降级组件

Step 5: Token 撤销

用户主动断开连接(取消授权)或你需要清理不再使用的 Token 时,调用撤销接口。
撤销后,该用户的 Access Token 和 Refresh Token 立即失效。后续 API 调用会收到 401。确保在撤销前已完成所有进行中的请求。
撤销的典型触发场景:
  • 用户在你的 App 设置页点击「断开袋袋连接」
  • 用户删除账号
  • 管理员批量清理不活跃授权
  • 检测到异常访问模式

Step 6: 安全存储

静态加密

Token 等同于用户凭证,在数据库中应加密存储:

安全清单

反模式

以下是生产环境中常见的 Token 管理错误,每一条都曾导致真实的线上事故。

1. 前端 localStorage 存储 Token

Token 应该只存在于服务端。前端通过 HttpOnly Cookie 或 Session ID 引用。

2. 忽略 onTokenRefresh 回调

刷新后旧 Refresh Token 已失效。如果新 Token 没有保存,下次刷新会失败,用户被迫重新授权。

3. 使用已轮换的 Refresh Token

每次从持久化存储读取最新 Token,不要依赖内存缓存。

4. 不处理并发刷新

参照 Step 3 的互斥锁模式。

生产环境清单

上线前逐项确认:
  • onTokenRefresh 已配置且写入持久化存储
  • Token 存储于服务端(DB / Redis),不在前端
  • Token 在存储层加密
  • 并发刷新有互斥锁保护
  • AuthExpired 有降级处理(引导重新授权)
  • 用户断开连接时调用 revokeToken() 清理
  • 日志不包含完整 Token 值
  • OAuth scope 遵循最小权限
  • 多实例部署使用分布式锁
  • 加密密钥不硬编码在代码中

下一步

Next.js 全栈集成

从零构建完整的 OAuth + 计费 Next.js 应用

Python FastAPI 集成

Python SDK + SQLAlchemy Token 持久化

Webhook 事件监听

接收并处理袋袋平台推送的实时事件

SDK 完整指南

双语言 API 详解与 Token 持久化