Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

AuthKeystone IDaaS 下游接入指南

AuthKeystone 是 OIDC 身份提供方(IDaaS),下游业务服务(ExoMind/wechat/…)通过标准 OIDC 接入。 本文档是下游接入的契约与规范——照着做,身份层零踩坑。定稿 2026-07-11。


1. 四层身份模型(务必理解)

AuthKeystone 的身份架构是四层正交,下游接入前必须分清:

字段语义下游怎么用
身份(Who)sub用户唯一稳定标识(= user_id,跨改名/换组织不变)用户主键:个人知识库、配额、偏好、会话——所有「按用户隔离」的场景都用它
组织(Whose)org_id组织容器(个人/团队/企业)仅团队/企业数据隔离;个人场景不需要。绝不用 org_id 当用户身份
权限(What)permissionsRBAC 权限列表授权判断(或调 auth check_permission)
客户端(Which)aud目标业务(client_id)验 token 时校验 aud == 自己的 client_id,防 token 跨业务误用

铁律sub = 用户身份主键,org_id = 组织容器。两者正交,绝不混用

  • ❌ 错误:用 org_id 做个人知识库 key(org_id=‘default’ 对所有 default 用户一样 → 串用户)
  • ✅ 正确:用 sub 做个人知识库 key(每人唯一),org_id 仅做团队空间隔离

2. 接入流程

2.1 在 auth 注册 OAuth client

平台管理员在 AuthKeystone 后台为你的服务创建 OAuth client,得到:

  • client_id / client_secret(机密客户端)或仅 client_id(公开客户端,前端 SPA,强制 PKCE)
  • redirect_uri(你的回调地址)
  • grant_types(authorization_code / password / client_credentials / refresh_token)

2.2 声明用哪些 scope(字段契约)

在 AuthKeystone 后台「OAuth 客户端 → Scope 配置」勾选你的服务需要的 scope。每个 scope 对应一组 claim(token 字段):

scope暴露的 claim谁该要
openid(默认,所有 client)sub所有
profilepreferred_username, name要展示用户名的(picture 头像字段规划中,暂不签发)
emailemail, email_verified要邮箱的
auth:permissionspermissions[]要做 RBAC 授权的
auth:orgorg_id要做团队/企业隔离的(个人场景不要
业务自定义(如 exomind:wiki业务约定特定业务,向 SaaS 申请

不声明的 scope → token 里没有对应 claim(最小暴露)。例如只要 openid + profile → token 只有 sub + preferred_username,拿不到 org_id/email/permissions

2.3 OIDC 授权码流程(Web 应用,推荐)

用户访问你的服务
  → 你重定向到 AuthKeystone 的 /authorize:
    https://auth.ai-as.cc/authorize?
      client_id=你的client_id
      &redirect_uri=你的回调
      &response_type=code
      &scope=openid+profile+email(你需要的)
      &state=随机(防CSRF)
      &code_challenge=PKCE(公开客户端必填)
  → 用户在 auth 登录(或已登录则自动 SSO)
  → auth 回调你的 redirect_uri?code=xxx&state=xxx
  → 你的后端用 code 换 token:
    POST https://auth.ai-as.cc/oauth/token
      grant_type=authorization_code
      code=xxx
      client_id / client_secret(机密)或 code_verifier(公开 PKCE)
    → 返回 {access_token, id_token, refresh_token}
  → 你的后端用 JWKS 公钥本地验签 id_token/access_token
  → 取 sub(user_id)做用户身份 + 按 permissions 授权
  → 发你自己的 session cookie

前端性能:预热到 auth.ai-as.cc 的连接(建议加)

用户点“AuthKeystone 登录“时,浏览器要从你的域名跳转到 auth.ai-as.cc。若此前没访问过该域名(或 DNS 缓存已过期),浏览器要现做 DNS 解析 + TCP 建连 + TLS 握手;跨公网、尤其移动网络 / 运营商 DNS 抖动时,这一步可能耗时 1 秒以上,用户会感觉“点了登录卡一下“。

在你的页面 <head> 加两行,让浏览器在用户浏览时就提前把这些做完

<link rel="dns-prefetch" href="//auth.ai-as.cc">
<link rel="preconnect" href="https://auth.ai-as.cc" crossorigin>
  • dns-prefetch:提前解析 auth.ai-as.cc 的 DNS
  • preconnect:进一步提前完成 DNS + TCP + TLS 握手(比 dns-prefetch 更彻底)
  • 两者叠加,用户点登录时直接复用已建立的连接,省掉那次 1s。

加在哪:所有“有 AuthKeystone 登录入口“的页面 <head>,或全局 layout 的 <head> 里。

有没有副作用:没有。纯性能优化,浏览器空闲时执行,不阻塞页面渲染、不影响功能和安全——加了只有好处,建议各业务都加。

2.4 登出 / 单点登出(SLO,必须做)

⚠️ 务必做:业务应用 logout 时,必须让浏览器跳到 AuthKeystone 的 /oidc/end_session 清掉 AuthKeystone 侧的 SSO 会话。只清业务应用自己的 session 不够。

为什么必须做:首次登录后 AuthKeystone 会在浏览器种一个 HttpOnly 的 auth_session SSO cookie(存活到 access_token 过期,默认 24h)。业务 logout 若不调 end_session

  • auth_session cookie 残留在浏览器
  • 用户再点登录 → /authorize 读到 cookie 有效 → 免密直接发 code(“自动登录”)
  • token 未过期(24h 内)就一直免密;过 24h 才重新要密码——这就是“有时候自动登录“的根因

怎么调(业务 logout 最后一步,浏览器顶层跳转):

https://auth.ai-as.cc/oidc/end_session?
  id_token_hint=<登录时拿到的 id_token>
  &post_logout_redirect_uri=<登出后回业务应用的地址>
参数必填作用
id_token_hint推荐登录时 /oauth/token 返回的 id_token。带它,auth 撤销该用户 access/refresh token + 删 session;不带只清 cookie
post_logout_redirect_uri可选登出后回业务应用的地址(须 http(s)://
  • 必须 window.location 浏览器跳转,不能 fetch——跨域请求不带 auth.ai-as.cc 的 cookie,清不掉 auth_session
  • 标准库可自动:发现文档已声明 end_session_endpoint,标准 OIDC SDK(Node openid-client / Python authlib / Java pac4j)发现后会自动在 logout 调用,通常无需手写。

2.5 验 token(JWKS 本地验签,推荐)vs introspect(实时查)

  • 本地验签(推荐):用 /.well-known/jwks.json 的 RS256 公钥本地验 token 签名 + 校验 aud=你的 client_id + exp 未过期。无状态,高性能。
  • introspect(备选):POST /oauth/introspect 实时查 token 有效性 + 权限。适合需要 token 实时状态(如已吊销)的场景。

3. OIDC 端点速查

端点用途
GET /.well-known/openid-configurationOIDC 发现文档(所有端点 + 支持的 scope/claim/grant)
GET /.well-known/jwks.jsonRS256 验签公钥(本地验 token)
GET /authorize授权码签发(用户登录入口)
POST /oauth/token换 token(authorization_code / password / refresh_token / client_credentials)
GET /api/userinfo用户信息(Bearer token → 标准 OIDC claims)
POST /oauth/introspecttoken 内省(实时查有效性 + 权限)
POST /oauth/revoketoken 吊销
GET /oidc/end_session单点登出(SLO)

4. token claim 详解

核心层(所有 token 必有,OIDC 协议级)

{
  "sub": "1",                    // user_id(字符串),用户唯一稳定主键
  "iss": "https://auth.ai-as.cc",
  "aud": "your_client_id",       // 你的 client_id(验 token 时校验)
  "exp": 1735689600,
  "iat": 1735603200,
  "jti": "unique-token-id"
}

扩展层(按 scope 暴露)

{
  "preferred_username": "zhangsan",   // scope=profile
  "email": "zs@example.com",           // scope=email
  "email_verified": true,
  "org_id": "default",                 // scope=auth:org(个人场景别要这个)
  "permissions": ["wiki:read", "wiki:write"]  // scope=auth:permissions
}

5. 关键规范(务必遵守)

  1. sub 做用户主键——这是 OIDC 标准,跨组织/改名/换租户都稳定。知识库、配额、会话、偏好,全用它。
  2. org_id 仅用于团队/企业隔离——做团队空间、企业数据隔离。个人场景(每个用户独立空间)用 sub,不要 org_id
  3. 验 token 时校验 aud = 你的 client_id——防止别的业务的 token 被你误用。
  4. 只声明你需要的 scope——最小暴露,AuthKeystone 会追踪谁用了哪些字段(迭代时评估影响)。
  5. 业务自定义 scope 走申请制——向 auth SaaS 管理员申请(如 exomind:wiki),不要擅自用未注册的 scope。
  6. logout 必须走 SLO——业务 logout 跳 /oidc/end_session(带 id_token_hint),否则 AuthKeystone 的 SSO cookie 残留,用户 24h 内点登录会免密“自动登录“。详见 2.4。

6. API Key(服务间,machine-to-machine)

如果你的服务是后端调用 auth(无用户交互),用 API Key:

  • 在 AuthKeystone 后台创建 API Key(绑权限范围 + 可选 account_key 资源隔离)。
  • 调用时 Authorization: Bearer sk_xxxX-API-Key: sk_xxx
  • POST /api/keys/validate 验证 key + 拿权限。

7. 常见错误(避坑)

错误后果正确
org_id/tenant_id 做用户主键串用户(default 下所有人共享一个 key)sub
username 做主键改名后身份断裂sub(user_id 稳定)
不校验 aud别的业务 token 被你误用验 aud = 你的 client_id
声明 auth:org scope 但个人场景多此一举(拿到 org_id=default 没用)个人场景只声明 openid+profile
token 当永久 session权限变更后不生效token 有 exp,过期 refresh;或用 introspect 实时查
logout 不调 /oidc/end_sessionAuthKeystone 的 SSO cookie 残留,用户 24h 内点登录免密自动登录logout 末尾浏览器跳 end_session(带 id_token_hint),见 2.4

8. 联调检查清单

下游接入联调时逐项确认:

  • OAuth client 注册(client_id/secret/redirect_uri/grant_types)
  • scope 声明(勾选你需要的)
  • 授权码流程跑通(/authorize → callback → /oauth/token)
  • token 验签(JWKS 本地 + aud 校验)
  • sub 读法正确(= user_id 字符串,做用户主键)
  • /userinfo 调通(按 scope 返 claim)
  • refresh_token 续期
  • 登录时保存 id_token(供 logout 作 id_token_hint)
  • 登出走 SLO(/oidc/end_session,带 id_token_hint)——必须,否则 SSO cookie 残留致免密自动登录(见 2.4)