跳转到内容

管理会话

查看 Markdown

登录是会话的起点,不是集成的终点。Session API 提供四个端点处理登录之后的会话生命周期:/refresh、/introspect、/logout、/revoke-all。本页是它们的唯一参考。

应用代码里优先使用对应语言的 Session SDK 包。手写这些 HTTP 调用前,建议先看 SDK 选择指南。

走 OIDC 流程的用户另请参考 OIDC 指南中的 /end-session —— 它有相关但更窄的用途。

端点 鉴权凭据 幂等? 影响范围
POST /refresh refresh token 本身 否(轮换 refresh token —— 每个令牌只能用一次) 单个会话
POST /introspect access token 本身 只读 单个会话
POST /logout refresh token 本身 是(两次调用都返回 revoked: true) 单个会话
POST /revoke-all Client-auth JWT(RS256) 是 某账户在调用应用下的所有会话

这四个端点都不需要额外的基础设施 —— 复用你最初集成时就已经有的密钥。

用 refresh token 换取一个新的 access token 和一个新的 refresh token。刷新采用严格轮换(OAuth 2.0 Security BCP §4.14.2):提交的已签名版本被消费,同一个逻辑 ApplicationSession 保持稳定的 payload sid,存入新的 jti,并把 payload rotationVersion 加一。请存下新的 refreshToken,并在下一次刷新时使用它。重复提交过旧版本会被视为失陷,并终态吊销这个会话。例外是近乎同时提交同一版本的请求(例如两个浏览器标签页):在短暂宽限窗口内,它们采用完全相同的胜出版本,不会再次推进版本或把用户登出。超过窗口后复用仍会触发失陷,所以始终只存储并发送最新令牌。

终端窗口
curl -X POST https://session-api.sudomimus.com/refresh \
-H "Content-Type: application/json" \
-d '{ "refreshToken": "..." }'

响应:

{
"accessToken": "<JWT>",
"refreshToken": "<轮换后的 JWT>",
"claims": {
"email": { "requirement": "REQUIRED", "state": "GRANTED" },
"firstName": { "requirement": "OPTIONAL", "state": "GRANTED" },
"lastName": { "requirement": "OFF", "state": "UNKNOWN" },
"staticAvatar": { "requirement": "SYNTHETIC_ONLY", "state": "UNKNOWN" },
"animatedAvatar": { "requirement": "OFF", "state": "UNKNOWN" }
}
}

请持久化轮换后的 refreshToken,替换掉你刚用过的那个 —— 旧的现在已经失效。claims 块与 /redeem 返回的逐条声明视图相同 —— 如何解读见 claims 块。

鉴权:无需 —— 持有 refresh token 即是凭据。

Session /refresh 只接受 Connect、Device、Native 等应用流程签发的 refresh token。OIDC refresh token 必须通过提供方的 /token 端点刷新,并使用 grant_type=refresh_token。

新的 access token 的 TTL 是最初 /redeem(或 /direct-issue/*)时算出的那一份;refresh 不会重新决议 TTL。

/refresh 的结果不只有成功或令牌被吊销。如果自上次签发令牌后,某条 required 声明不再满足,例如开发者将策略从 optional 改为 required,或用户撤销授权,本次刷新会返回 ClaimConsentRequired,而不会签发缺少该声明的令牌。

补救方式取决于客户端类型,因为 /refresh 自己无法收集同意:

  • 原生客户端(Steam / AccessKey)靠重新跑一次原本的 direct-issue 来补救,它会返回一个 Errand 交接,让用户授予同意。
  • 浏览器应用靠再次引导用户走一次常规交互式登录来补救。

这在实践中很少见 —— 只在策略或授权于会话中途变化时才会发生 —— 但请把你的刷新路径设计成弹出重新认证提示,而不是把每一次刷新失败都当成强制登出。

/introspect —— 这个令牌还有效吗

Section titled “/introspect —— 这个令牌还有效吗”

向 Sudomimus 查询某个 access token 的当前状态。用它实现「跨服务及时撤销会话」—— 例如用户点击「在所有设备退出」后,希望其他标签页或服务能在有限时间内察觉。

终端窗口
curl -X POST https://session-api.sudomimus.com/introspect \
-H "Content-Type: application/json" \
-d '{ "accessToken": "..." }'

响应:

{
"status": "active",
"recommendedRecheckSeconds": 600
}

status 可取:

  • "active" —— sid 解析到 ACTIVE 且权威仍有效的 ApplicationSession。
  • "revoked" —— 会话已被终态吊销,或某项权威绑定不再有效。
  • "expired" —— ApplicationSession 的固定过期时间已到。
  • "not_found" —— 令牌无效,或其 sid 找不到匹配会话。

recommendedRecheckSeconds 是 Sudomimus 建议的缓存时长,超过之后再次 introspect。目前总是 600 秒。把 access token 自己的 exp 当作有效期上限;introspect 是用来及时发现撤销的,不是用来替代签名验证。

鉴权:无需 —— access token 本身就是凭据。任何持有该令牌的一方都能问它是否还有效。

本地签名验证负责正确性;introspect 负责新鲜度。一个合理的搭配:

  • 每次请求都本地验证 access token 的签名和 exp(开销很小)。
  • 机会主义地调 /introspect —— 每 N 分钟一次、放进后台任务,或者在用户可见的状态变化后调用。

不要每次请求都 introspect,否则就失去了使用签名令牌的初衷。

用任意一个真实的 refresh-token 版本终态吊销其 ApplicationSession。对应 access token 在 /introspect 上不再被报告为 active,此后该 sid 的所有 /refresh 都会失败。

终端窗口
curl -X POST https://session-api.sudomimus.com/logout \
-H "Content-Type: application/json" \
-d '{ "refreshToken": "..." }'

响应:

{ "revoked": true }
  • revoked: true —— 会话被吊销(或者本来已是终态;重复调用没问题)。
  • revoked: false —— 令牌无效或未找到。

鉴权:无需 —— 持有 refresh token 即可对这个会话登出(RFC 7009 风格)。

/revoke-all —— 吊销账户所有会话

Section titled “/revoke-all —— 吊销账户所有会话”

吊销一个用户在调用应用中的所有现有会话。这个端点适用于账户被盗后的应急处置、「在所有设备上退出登录」以及由支持人员发起的会话终止。与 /logout 一样,已签发的 access token 在 exp 之前仍可能通过离线验证。

账户通过其 扇区主体(sector subject) 标识 —— 即应用 access/refresh token 受保护 header 中的 sub,也是你用来标识用户的值。

终端窗口
curl -X POST https://session-api.sudomimus.com/revoke-all \
-H "Content-Type: application/json" \
-H "Authorization: SudomimusClientJWT $SUDOMIMUS_CLIENT_AUTH_JWT" \
-d '{ "subject": "sub_9SQ5535CRWNDDM2T" }'

响应:

{ "revoked": true }

revoked: true 表示请求已被接受。对于不存在或不属于当前 sector 的 subject,端点同样返回相同响应,以免泄露该 subject 是否存在。

鉴权:需要 client-auth JWT,签名方式与 /establish 相同,但 aud 必须是 "sudomimus-session"。操作范围是隐式的 —— 只触及调用应用下签发给该账户的会话。无法用某应用的 client-auth 密钥撤销另一个应用的会话。

stateDiagram-v2
    state "活跃的 ApplicationSession" as Active
    state "Refresh 轮换" as Rotating
    state "已吊销" as Revoked
    state "已过期" as Expired

    [*] --> Active: 初始令牌签发

    Active --> Rotating: 用当前 refresh token 调用 /refresh
    Rotating --> Active: 新 access + 轮换后的 refresh
    Rotating --> Active: grace window 内的上一版本采用胜出结果

    Active --> Active: /introspect = active
    Active --> Revoked: grace window 后重用旧 refresh token
    Active --> Revoked: /logout 或 /revoke-all
    Active --> Revoked: 实时权威失效
    Active --> Expired: 到达固定会话过期时间

    Revoked --> Revoked: /introspect = revoked
    Revoked --> [*]
    Expired --> [*]

OIDC 风格的 refresh 见 OIDC 接入方 —— Refresh。

OIDC 刷新失败时,见OIDC 排错。