一、引言
当一个组织决定用 OAuth 2.0 / OpenID Connect 构建自己的统一登录系统时,两个工程问题立刻浮出水面:
- 会话与 Token 管理:一个用户登录一次,多个子系统各自获得独立的 access_token,这些 token 的签发、存储、刷新、撤销机制是什么?
- Token 验证:子系统拿着 access_token 去调用 Web API,API 端如何验证这个 token 的真伪和权限?是否每次都要回调授权服务器?
本文将这两个问题的完整技术方案串联起来,覆盖从用户输入密码的第一刻,到 token 在 API 端被验证的最后一步。
二、架构总览
┌─────────────────────────────── 组织内部 ───────────────────────────────┐ │ │ │ auth.company.com │ │ ┌──────────────────┐ │ │ │ 授权服务器 │ │ │ │ │ │ │ │ • 用户账号数据库 │ │ │ │ • SSO 会话管理 │ │ │ │ • Token 签发/撤销│ │ │ │ • JWKS 公钥端点 │ │ │ └────────┬─────────┘ │ │ │ │ │ ┌─────────────────┼─────────────────┐ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │ │ CRM 系统 │ │ OA 系统 │ │ 商城系统 │ ← 子系统 │ │ │ 前端 + 后端 │ │ 前端 + 后端 │ │ 前端 + 后端 │ (OAuth 客户端)│ │ └──────┬─────┘ └──────┬─────┘ └─────┬──────┘ │ │ │ │ │ │ │ │ access_token │ access_token │ access_token │ │ ▼ ▼ ▼ │ │ ┌────────────────────────────────────────────────────┐ │ │ │ Web API 层 / API 网关 │ │ │ │ 验证 access_token → 返回受保护资源 │ │ │ └────────────────────────────────────────────────────┘ │ └───────────────────────────────────────────────────────────────────────┘这套架构中存在三层会话/凭证体系,各层职责清晰、互不耦合:
| 层级 | 凭证 | 作用域 | 持有者 |
|---|---|---|---|
| 第一层 | SSO Session Cookie (auth_sid) | 授权服务器域名 | 浏览器 |
| 第二层 | 子系统 Session Cookie (crm_sid) | 子系统域名 | 浏览器 |
| 第三层 | access_token + refresh_token | 子系统后端 → API | 子系统后端 |
三、SSO 登录:一次认证,处处通行
3.1 首次登录——以 CRM 为起点
用户首次访问 CRM 系统,触发完整的 OAuth 授权流程:
用户浏览器 CRM 后端 授权服务器 │ │ │ │ GET /dashboard │ │ │ (无 crm_sid) │ │ │────────────────────▶│ │ │ │ │ │ 302 → auth.company.com/authorize │ │ ?response_type=code │ │ &client_id=crm-system │ │ &scope=openid profile email │ │ &redirect_uri=crm.company.com/callback │ │ &state=随机值 │ │◀────────────────────│ │ │ │ │ GET /authorize(无 auth_sid) │ │─────────────────────────────────────────────▶│ │ │ │ 返回登录页面 │ │◀─────────────────────────────────────────────│ │ │ │ POST 用户名 + 密码(可能还有 MFA) │ │─────────────────────────────────────────────▶│ │ │ │ 验证通过,授权服务器建立 SSO 会话: │ │ Set-Cookie: auth_sid=xxx │ │ (domain=auth.company.com; HttpOnly; Secure) │ │ │ │ 内部系统,跳过授权确认页,直接签发 code │ │ 302 → crm.company.com/callback?code=abc │ │◀─────────────────────────────────────────────│ │ │ │ GET /callback?code=abc&state=xxx │ │────────────────────▶│ │ │ │ │ │ │ POST /token │ │ │ code + client_secret │ │ │───────────────────────▶│ │ │ │ │ │ { access_token, │ │ │ refresh_token, │ │ │ id_token } │ │ │◀───────────────────────│ │ │ │ │ CRM 建立自己的 session │ │ Set-Cookie: crm_sid=yyy │ │ 302 → /dashboard │ │◀────────────────────│ │登录完成后,浏览器中的 Cookie 状态:
auth.company.com → auth_sid=xxx (SSO 会话) crm.company.com → crm_sid=yyy (CRM 会话)3.2 访问第二个系统——SSO 静默登录
用户随后访问 OA 系统,不需要再次输入密码:
用户浏览器 OA 后端 授权服务器 │ │ │ │ GET oa.company.com/home │ │ (无 oa_sid) │ │ │────────────────────▶│ │ │ │ │ │ 302 → auth.company.com/authorize │ │ ?client_id=oa-system │ │◀────────────────────│ │ │ │ │ GET /authorize │ │ Cookie: auth_sid=xxx ← 浏览器自动携带! │ │─────────────────────────────────────────────▶│ │ │ │ 授权服务器验证 auth_sid: │ │ ✓ 会话有效 │ │ ✓ 用户已认证 │ │ ✓ OA 是已授权的内部系统 │ │ │ │ 直接签发 code,无需登录、无需确认 │ │ 302 → oa.company.com/callback?code=def │ │◀─────────────────────────────────────────────│ │ │ │ 后续流程与 CRM 相同(code 换 token、建 session)│ │ │ │ 用户感知:页面闪了一下,直接进入了 OA │SSO 的本质:授权服务器的auth_sidCookie 在浏览器访问auth.company.com时自动携带。只要这个会话有效,任何子系统跳转过来都会被静默签发 code,用户无需再次输入密码。
四、Token 签发:独立隔离的多 Token 体系
4.1 核心原则:每个子系统获得完全独立的 Token 对
授权服务器为同一个用户、不同的子系统,签发完全不同的 token:
同一用户 zhangsan 在三个系统中的 token: ┌───────────────────┬───────────────────┬───────────────────┐ │ CRM 的 token │ OA 的 token │ 商城的 token │ ├───────────────────┼───────────────────┼───────────────────┤ │ client_id: │ client_id: │ client_id: │ │ crm-system │ oa-system │ mall-system │ │ │ │ │ │ scope: │ scope: │ scope: │ │ profile email │ profile │ profile orders │ │ │ │ │ │ audience: │ audience: │ audience: │ │ crm-api │ oa-api │ mall-api │ │ │ │ │ │ access_token: │ access_token: │ access_token: │ │ eyJ...AAA │ eyJ...BBB │ eyJ...CCC │ │ (各不相同) │ (各不相同) │ (各不相同) │ │ │ │ │ │ refresh_token: │ refresh_token: │ refresh_token: │ │ rf_111 │ rf_222 │ rf_333 │ │ │ │ │ │ 过期/刷新/撤销: │ 过期/刷新/撤销: │ 过期/刷新/撤销: │ │ 各自独立 │ 各自独立 │ 各自独立 │ └───────────────────┴───────────────────┴───────────────────┘为什么不共用一个 token?
| 共用 token 的风险 | 独立 token 的优势 |
|---|---|
| CRM 的 token 可以访问 OA 的 API → 越权 | 最小权限:每个 token 只能访问对应系统的 API |
| 一个系统泄露 = 所有系统沦陷 | 爆炸半径最小化:泄露只影响一个系统 |
| 无法针对单个系统撤销访问 | 可以精确撤销某个系统的 token |
| 所有系统共享同一个过期时间 | 不同系统可以设置不同的过期策略 |
4.2 授权服务器内部的存储结构
┌──────────────────────────── 授权服务器数据库 ────────────────────────────┐ │ │ │ SSO Sessions 表 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ session_id │ user_id │ login_time │ expires_at │ │ │ ├─────────────┼───────────┼─────────────┼──────────────┤ │ │ │ auth_sid_001│ zhangsan │ 09:00 │ 17:00 │ │ │ │ auth_sid_002│ lisi │ 09:30 │ 17:30 │ │ │ └─────────────┴───────────┴─────────────┴──────────────┘ │ │ │ │ Token Grants 表 │ │ ┌────────┬───────────┬────────────┬──────────┬──────────┬───────────┐ │ │ │token_id│ user_id │ client_id │ session │ scope │ status │ │ │ ├────────┼───────────┼────────────┼──────────┼──────────┼───────────┤ │ │ │ t_001 │ zhangsan │ crm-system │ sid_001 │ profile │ active │ │ │ │ t_002 │ zhangsan │ oa-system │ sid_001 │ profile │ active │ │ │ │ t_003 │ zhangsan │ mall-system│ sid_001 │ orders │ active │ │ │ │ t_004 │ lisi │ crm-system │ sid_002 │ profile │ active │ │ │ └────────┴───────────┴────────────┴──────────┴──────────┴───────────┘ │ │ │ │ 关系:SSO Session (1) ──→ (N) Token Grants │ │ 意义:可以通过销毁 session 来级联管理其下所有 token │ └────────────────────────────────────────────────────────────────────────┘4.3 管理维度
基于上述数据结构,授权服务器可以从三个维度管理 token:
维度一:按用户 "查看 zhangsan 的所有活跃授权" → t_001, t_002, t_003 "撤销 zhangsan 的所有 token" → 员工离职场景 维度二:按子系统 "查看 crm-system 的所有活跃用户" → zhangsan, lisi "撤销 crm-system 的所有 token" → 系统下线场景 维度三:按 SSO 会话 "销毁 auth_sid_001" → zhangsan 需要重新输入密码 → 可选:同时撤销该 session 下的 t_001, t_002, t_003五、日常使用:双层代理调用链路
用户登录完成后,日常的每一次 API 调用都经过两层代理:
前端 CRM 后端 Web API (只知道 Cookie) (持有 access_token) (验证 token) GET /api/orders │ │ Cookie: crm_sid=yyy │ │ ───────────────────────▶│ │ │ │ ┌──────┴──────┐ │ │ 验证 session │ │ │ crm_sid 有效?│ │ │ 用户已认证? │ │ └──────┬──────┘ │ │ │ ┌──────┴──────┐ │ │ 检查 token │ │ │ 是否即将过期 │──→ 是 → 触发刷新 │ └──────┬──────┘ (见第六章) │ │ 否 │ │ │ │ GET /v1/orders │ │ Authorization: │ │ Bearer eyJ...AAA │ │─────────────────────────────▶│ │ │ │ ┌──────┴──────┐ │ │ 验证 token │ │ │ (见第七章) │ │ └──────┬──────┘ │ │ │ 200 OK │ │ [{ orderId, ... }] │ │◀─────────────────────────────│ │ │ 200 OK │ │ [{ orderId, ... }] │ │ ◀───────────────────────│ │前端完全不知道 OAuth 的存在——它只认识 Cookie,和传统的 Session 认证体验完全一致。所有 token 操作都在后端闭环完成。
六、Token 刷新:后端静默续期
access_token 有效期通常只有 5~60 分钟。过期后由子系统后端自行刷新,前端全程无感知。
6.1 刷新触发策略
生产环境中通常两种策略并用:
策略一:主动刷新(主防线) ┌────────────────────────────────┐ │ 每次 API 调用前检查: │ │ if (now > tokenExpiresAt - 60s)│ ← 提前 60 秒刷新 │ → 先刷新,再调 API │ │ 优点:避免无谓的失败请求 │ └────────────────────────────────┘ 策略二:被动刷新(兜底) ┌────────────────────────────────┐ │ 调 API 收到 401 时: │ │ → 刷新 token │ │ → 用新 token 重试原始请求 │ │ 优点:不依赖本地时钟准确性 │ └────────────────────────────────┘6.2 刷新流程
CRM 后端 授权服务器 │ │ │ 检测到 access_token 即将过期 │ │ │ │ POST /token │ │ grant_type=refresh_token │ │ &refresh_token=rf_111 │ │ &client_id=crm-system │ │ &client_secret=*** │ │─────────────────────────────────────────▶│ │ │ │ 授权服务器检查: │ │ ✓ refresh_token 有效 │ ✓ 未被撤销 │ │ ✓ 客户端身份正确 │ │ ✓ 用户未被禁用 │ ← 关键检查点! │ │ │ { │ │ "access_token": "eyJ...NEW", │ │ "expires_in": 900, │ │ "refresh_token": "rf_444" ← 可能轮换 │ │ } │ │◀─────────────────────────────────────────│ │ │ │ 更新 session 中的 token │ │ 继续执行原始 API 调用 │刷新是 Token 撤销的关键拦截点。即使 access_token 是 JWT 无法实时撤销,只要 refresh 请求到达授权服务器,就可以通过拒绝刷新来阻断访问。这就是为什么将 access_token 有效期设短(5~15 分钟)能有效弥补 JWT 无法实时撤销的缺陷。
6.3 并发刷新的竞态处理
当多个前端请求同时触发 token 过期检测,必须避免并发刷新:
无锁情况(错误): 请求 A → 检测过期 → 用 rf_111 刷新 → 获得 rf_444 ✓ 请求 B → 检测过期 → 用 rf_111 刷新 → rf_111 已被轮换 → 失败 ✗ 请求 C → 检测过期 → 用 rf_111 刷新 → rf_111 已被轮换 → 失败 ✗ 有锁情况(正确): 请求 A → 检测过期 → 获取刷新锁 → 用 rf_111 刷新 → 获得 rf_444 ✓ → 释放锁 请求 B → 检测过期 → 锁已被占用 → 等待 → 复用 rf_444 的新 token ✓ 请求 C → 检测过期 → 锁已被占用 → 等待 → 复用 rf_444 的新 token ✓实现方式:
letrefreshPromise=null;asyncfunctionensureValidToken(session){if(Date.now()<session.tokenExpiresAt-60000)return;// 复用已有的刷新请求if(refreshPromise)returnrefreshPromise;refreshPromise=doRefresh(session).finally(()=>{refreshPromise=null;});returnrefreshPromise;}七、Token 验证:Web API 端的两种方案
这是整条链路中最关键的安全环节——Web API 如何判断一个 access_token 是否合法。
7.1 方案一:不透明 Token + Introspection(实时回调)
当 access_token 是一个无意义的随机字符串时,API 端无法自行解析,必须回调授权服务器。
access_token = "a3f7b2c1d4e5f6a8" ← 无法解析,只是一个引用 Web API 授权服务器 │ │ │ POST /introspect │ │ Authorization: Basic base64(api_id:api_secret) │ │ token=a3f7b2c1d4e5f6a8 │ │─────────────────────────────────────────────────▶│ │ │ │ 授权服务器查数据库,返回 token 状态:│ │ │ │ { │ │ "active": true, ← 核心字段 │ │ "sub": "zhangsan", ← 用户标识 │ │ "client_id": "crm-system",← 哪个客户端的 │ │ "scope": "profile email", ← 权限范围 │ │ "exp": 1716048000 ← 过期时间 │ │ } │ │◀─────────────────────────────────────────────────│ │ │ │ if active == true && scope 包含所需权限 → 放行 │ │ if active == false → 401 Unauthorized │特性分析: ✓ 实时撤销:token 一旦被标记无效,下一次 API 调用立刻失败 ✓ 授权服务器完全掌控:任何时刻都能让任何 token 失效 ✗ 性能:每次 API 调用增加一次网络往返 ✗ 可用性:授权服务器宕机 → 所有 API 调用失败 ✗ 扩展性:高并发场景下授权服务器成为瓶颈7.2 方案二:JWT Token + 本地验签(无需回调)
当 access_token 是一个 JWT 时,它自身就包含了验证所需的全部信息:
access_token = "eyJhbGciOiJSUzI1NiIsImtpZCI6InJzYS0xIn0.eyJpc3Mi..." 解码后: Header: { "alg": "RS256", "kid": "rsa-1" } Payload: { "iss": "https://auth.company.com", // 签发者 "sub": "zhangsan", // 用户 "aud": "crm-api", // 受众 "client_id": "crm-system", // 客户端 "scope": "profile email", // 权限 "roles": ["sales", "manager"], // 角色(自定义) "exp": 1716048000, // 过期时间 "iat": 1716044400, // 签发时间 "jti": "unique-token-id-001" // 唯一标识 } Signature: RS256_SIGN(header + "." + payload, 授权服务器私钥)验证流程——全部在 Web API 本地完成:
┌───────────────────────────────────────────────────────────┐ │ 第一步:获取公钥(仅首次/缓存过期时需要网络请求) │ │ │ │ GET https://auth.company.com/.well-known/jwks.json │ │ │ │ → { "keys": [{ │ │ "kid": "rsa-1", │ │ "kty": "RSA", │ │ "n": "公钥模数...", │ │ "e": "AQAB" │ │ }]} │ │ │ │ 缓存到内存,有效期 24 小时 │ │ 此后所有验证不再需要网络请求 │ └──────────────────────────┬────────────────────────────────┘ │ ┌──────────────────────────▼────────────────────────────────┐ │ 第二步:验证签名 │ │ │ │ 从 JWT header 中取出 kid="rsa-1" │ │ 从缓存中找到对应公钥 │ │ RSA_VERIFY(header + "." + payload, signature, 公钥) │ │ │ │ ✓ 通过 → 证明 token 确实由授权服务器签发,未被篡改 │ │ ✗ 失败 → 401(伪造或篡改的 token) │ └──────────────────────────┬────────────────────────────────┘ │ ┌──────────────────────────▼────────────────────────────────┐ │ 第三步:验证声明(Claims) │ │ │ │ ✓ exp > 当前时间 → token 未过期 │ │ ✓ iss == "https://auth.company.com" → 签发者正确 │ │ ✓ aud 包含当前 API 标识 → token 是给我用的 │ │ ✓ scope 包含当前操作所需权限 → 权限充足 │ │ │ │ 全部通过 → 放行请求,从 payload 中提取用户身份用于业务逻辑 │ └───────────────────────────────────────────────────────────┘网络请求次数统计:
不透明 Token: 每次 API 调用 = 1 次 Introspection 回调 JWT: API 服务启动后首次 = 1 次(获取 JWKS 公钥) 后续每次 API 调用 = 0 次(纯本地计算) 公钥缓存过期后 = 1 次(重新获取) 一天处理 100 万次 API 调用: 不透明 Token → 100 万次回调 JWT → 1 次公钥获取7.3 JWT 的撤销困境与解决方案
JWT 本地验证的代价是无法实时撤销:
09:00 签发 JWT(有效期 1 小时,exp=10:00) 09:15 管理员在授权服务器撤销该用户的所有 token 09:16 用户持 JWT 调 API → 签名正确、未过期 → 放行 ✗ ... 10:00 JWT 到期,自然失效 10:01 子系统尝试用 refresh_token 刷新 → 授权服务器拒绝 → 访问阻断 ✓ 漏洞窗口:09:15 ~ 10:00(45 分钟)三级解决方案:
┌─────────────────────────────────────────────────────────────────┐ │ 方案一:缩短有效期(最常用,低成本) │ │ │ │ access_token 有效期 = 5 分钟 │ │ 漏洞窗口 = 最多 5 分钟 │ │ 代价:refresh 频率增加(每 5 分钟一次) │ │ 大多数业务场景可接受 │ ├─────────────────────────────────────────────────────────────────┤ │ 方案二:Token 黑名单(中等成本,高实时性) │ │ │ │ 授权服务器撤销 token 时: │ │ → 将 jti 推送到 Redis/消息队列 │ │ → 所有 API 服务订阅并维护本地黑名单 │ │ │ │ 验证 JWT 时增加一步:检查 jti 是否在黑名单中 │ │ 黑名单很小(只存被主动撤销且未过期的 token,过期自动清除) │ │ 额外延迟:亚毫秒级(本地 Redis 查询) │ ├─────────────────────────────────────────────────────────────────┤ │ 方案三:分级验证(高安全场景) │ │ │ │ 低敏感操作(读取数据):JWT 本地验证 │ │ 高敏感操作(转账/删除/改权限):JWT + Introspection 双重验证 │ │ │ │ 在安全性和性能之间按操作敏感度动态选择 │ └─────────────────────────────────────────────────────────────────┘7.4 两种方案完整对比
不透明 Token JWT + Introspection + 本地验签 ──────────────────────────────────────────────────────────── 验证方式 回调授权服务器 本地公钥验签 每次 API 调用网络开销 1 次往返 0 次 授权服务器依赖 强依赖(宕机=全挂) 弱依赖(仅获取公钥) 实时撤销 ✓ 即时生效 ✗ 有窗口期 token 体积 小(几十字节) 大(几百字节~几KB) API 端扩展性 受限于授权服务器吞吐 无状态,任意水平扩展 实现复杂度 低(调接口即可) 中(需管理公钥缓存) 信息自包含 否 是(可直接读取用户信息)八、生产环境的主流选择
┌─────────────────────────────────────────────────────────────┐ │ 业界共识(2024+) │ │ │ │ access_token: │ │ 格式 = JWT(自包含,本地验签) │ │ 有效期 = 5~15 分钟(短期,弥补无法实时撤销) │ │ 验证 = 本地公钥验签,高危操作可叠加 Introspection │ │ │ │ refresh_token: │ │ 格式 = 不透明随机字符串(不需要本地验签能力) │ │ 有效期 = 7~30 天 │ │ 验证 = 必然回调授权服务器(刷新本身就是后端通道请求) │ │ 轮换 = 推荐启用 Rotation(每次刷新签发新 refresh_token) │ │ │ │ 为什么 access_token 用 JWT 而 refresh_token 不用? │ │ │ │ access_token 的消费者是 Web API: │ │ → 可能有几十个微服务需要验证 │ │ → 需要高性能、低延迟、去中心化验证 │ │ → JWT 的自包含特性完美匹配 │ │ │ │ refresh_token 的消费者只有授权服务器的 Token 端点: │ │ → 只有一个目标,必然是网络请求 │ │ → 不需要"本地验证"的能力 │ │ → 不透明字符串反而更安全(不暴露内部声明信息) │ └─────────────────────────────────────────────────────────────┘九、全局登出:级联清理
SSO 架构下的登出比单系统复杂得多,需要协调多层会话的清理:
用户在 CRM 点击"退出所有系统" │ ▼ CRM 后端处理: ① 销毁 CRM 自己的 session(crm_sid 作废) ② 重定向到 auth.company.com/logout │ ▼ 授权服务器处理: ① 销毁 SSO 会话(auth_sid 作废) ② 查找该 session 下所有已授权的子系统 ③ 向每个子系统发送 Back-Channel Logout 通知: POST https://oa.company.com/backchannel-logout logout_token=eyJ...(包含 sub 和 session_id) POST https://mall.company.com/backchannel-logout logout_token=eyJ... ④ 撤销该 session 下签发的所有 refresh_token │ ▼ 各子系统收到通知后: 销毁对应用户的 session 丢弃存储的 access_token 和 refresh_token │ ▼ 最终状态: 浏览器中的 auth_sid、crm_sid、oa_sid、mall_sid 全部失效 所有 refresh_token 在授权服务器端被标记为已撤销 残余的 JWT access_token 在几分钟内自然过期十、凭证生命周期全景图
时间 ─────────────────────────────────────────────────────────────────────→ 09:00 用户输入密码 │ ├──→ SSO Session 诞生(auth_sid,有效 8 小时) │ ├──→ code 诞生 ──→ 换取 token ──→ code 死亡(一次性,永久作废) │ │ │ ├──→ CRM access_token₁(JWT,15分钟) │ │ │ │ │ ├── 用于调 API(本地验签,无回调) │ │ └── 09:15 过期 → 死亡 │ │ │ └──→ CRM refresh_token₁(不透明,30天) │ │ │ ├── 09:14 主动刷新 │ │ → access_token₂(又活 15 分钟) │ │ → refresh_token₂(轮换) │ │ │ └── 每 15 分钟循环一次... │ 09:15 用户访问 OA(SSO 静默登录,无需密码) │ ├──→ 新 code 诞生 → 换取 token → code 死亡 │ │ │ ├──→ OA access_token₁(独立的 token) │ └──→ OA refresh_token₁(独立的刷新链) │ 17:00 SSO Session 过期 │ └── 新系统接入需要重新输入密码 已有 session 的子系统不受影响(直到自己的 token 链断裂) 某日 refresh_token 最终过期 → 该子系统 session 失效 → 跳转授权服务器 → SSO Session 有效?静默重新获取 token → SSO Session 也过期?重新输入密码十一、总结
自建 OAuth 统一登录架构可以归纳为三个分离原则和一个核心取舍:
三个分离:
- 认证与业务分离——密码验证、MFA、账号管理集中在授权服务器,子系统永远不接触密码
- 会话与 Token 分离——SSO Session 管理"用户是否登录过",Token 管理"子系统能访问什么 API",各自有独立的生命周期
- Token 签发与验证分离——授权服务器用私钥签发 JWT,Web API 用公钥验证,两者无需实时通信
一个核心取舍:
JWT 本地验签带来了性能和可用性的巨大收益(无需每次回调授权服务器),代价是撤销的实时性。业界通过缩短 JWT 有效期(5~15 分钟)+ refresh_token 刷新时拦截的方式,将这个代价控制在可接受范围内。对于极高安全要求的操作,可以叠加 Introspection 实时校验作为补充。
这套设计让一个用户的一次密码输入,安全、高效地转化为多个子系统的持久会话、多个独立的 API 访问凭证,以及可集中管控的全局会话管理能力。