easyai-ai-gateway/docs/oidc-jit-provisioning.md
chengcheng 46bac51703 feat: 将 Gateway Web 迁移到 BFF 会话
浏览器只通过 HttpOnly Cookie 恢复统一认证状态,不再访问认证中心 Token Endpoint 或保存 OIDC Token。同步更新错误提示、部署配置和接入文档。
2026-07-13 19:09:57 +08:00

5.9 KiB
Raw Permalink Blame History

Auth Center OIDC 用户受控 JIT 预配

适用边界

Gateway 只在 OIDC Token 已通过签名、Issuer、Audience、有效期、tid、Scope 和应用角色校验后执行 JIT。认证中心的稳定 sub 是外部用户标识Gateway 不读取、不保存或公开 Keycloak 内部 ID也不向 Token 增加 gatewayUserId

本次保持单 Gateway 租户:部署方用 OIDC_GATEWAY_TENANT_KEY 把 Auth Center 的已验证 tid 显式绑定到一个已存在、启用且配置了启用中默认用户组的 Gateway 租户。Token 不能创建租户。

配置

OIDC_ENABLED=true
OIDC_JIT_PROVISIONING_ENABLED=true
OIDC_GATEWAY_TENANT_KEY=default
OIDC_BROWSER_SESSION_ENABLED=true
OIDC_SESSION_COOKIE_SECURE=false # 本地 HTTP生产必须为 true
OIDC_CLIENT_ID=<Control Plane 生成的公共 Client ID>
OIDC_REDIRECT_URI=http://localhost:8088/api/v1/auth/oidc/callback
OIDC_POST_LOGOUT_REDIRECT_URI=http://localhost:5178/
OIDC_SESSION_ENCRYPTION_KEY=<独立的 32 字节随机密钥base64 编码>
OIDC_SESSION_IDLE_TTL_SECONDS=1800
OIDC_SESSION_ABSOLUTE_TTL_SECONDS=28800
OIDC_SESSION_REFRESH_BEFORE_SECONDS=60
  • OIDC_JIT_PROVISIONING_ENABLED 默认 false。关闭时停止创建新用户,但已有 source=oidc + external_user_id=sub 映射仍会解析和同步登录时间。
  • JIT 开启时 OIDC_GATEWAY_TENANT_KEY 必填,缺失会使 Gateway 启动失败。
  • 本地与 Staging 验收环境应在各自 Git 忽略或 Secret 管理的环境文件中显式开启;生产启用需独立变更审批。

Web Console 浏览器会话

  • Web 只跳转 GET /api/v1/auth/oidc/login。Gateway 生成 state、nonce、PKCE verifier并以 Authorization Code + PKCE S256 完成换码;公共 Client 请求只发送 client_id,不使用 Client Secret。
  • Access Token、Refresh Token 和 ID Token 使用 AES-256-GCM 加密后存入 PostgreSQL数据库只保存随机 Session Cookie 的 SHA-256。浏览器 JavaScript、响应体和 Web Storage 均不接触 Token。
  • 浏览器只保存 32 字节随机、HttpOnly + SameSite=Strict 的 Session Cookie。新标签页通过该 Cookie 调用 /api/v1/me 恢复登录态Gateway 不签发第二枚 JWT。
  • Access Token 继续保持 5 分钟。认证请求发现剩余时间不超过 60 秒时使用 Refresh Token 自动刷新;多实例通过 PostgreSQL 刷新租约保证同一版本只刷新一次,并原子保存旋转后的 Refresh Token。
  • Session 闲置 30 分钟、绝对最长 8 小时。闲置 530 分钟后的首个请求可自动刷新;超过闲置或绝对期限不会刷新,必须重新登录。浏览器不运行定时刷新。
  • 所有 Web API 请求使用 credentials: include。Cookie 鉴权的 POST、PUT、PATCH、DELETE 必须携带 CORS_ALLOWED_ORIGIN 白名单中的 Origin否则返回结构化 403。
  • Staging、生产及其他非本地环境启动时强制 OIDC_SESSION_COOKIE_SECURE=true,并拒绝带 * 的凭据型 CORS 配置。本地 HTTP 开发和自动化测试可以显式设为 false
  • POST /api/v1/auth/oidc/logout 校验可信 Origin、删除本地 Session、使用公共 Client ID 撤销 Refresh Token并跳转 Auth Center 退出地址;DELETE /api/v1/auth/oidc/session 保留为幂等的本地删除接口。
  • OIDC_SESSION_ENCRYPTION_KEY 必须来自 Git 忽略的本地文件、Kubernetes Secret 或 Secret Manager不得复用 JWT Secret。关闭 OIDC_BROWSER_SESSION_ENABLED 可停止新会话;回滚镜像后已创建记录作为惰性数据保留。

数据和事务语义

  • 查找键固定为 source=oidc + external_user_id=subuser_key 由规范化 Issuer 和 sub 做 SHA-256 派生,不按邮箱、手机号、昵称匹配。
  • 首次登录在一个事务中创建 gateway_users 投影、绑定租户默认用户组、初始化 resource 钱包并写入 identity.oidc_user.provisioned 审计事件。
  • 重复或并发登录依赖现有唯一约束和冲突处理返回同一个本地用户,不重复创建钱包或首次预配审计。
  • 后续登录只同步 Token 用户名、应用角色、last_login_atsynced_atsource_updated_at;不覆盖人工资料或用户组,不重新启用已禁用/删除账号。
  • JIT 不生成 API Key 或任何 secret。用户仅在主动创建 API Key 或进入需要 Key 的工作流时触发生命周期操作。

对外错误

所有错误沿用 ErrorEnvelope

HTTP code 含义
403 GATEWAY_USER_NOT_PROVISIONED JIT 关闭且没有已有本地映射
403 GATEWAY_USER_DISABLED 本地用户已禁用或删除
503 GATEWAY_TENANT_UNAVAILABLE 配置租户或用户组不存在/未启用
503 GATEWAY_USER_PROVISIONING_FAILED 事务或存储故障;响应不暴露内部错误
404 OIDC_BROWSER_SESSION_DISABLED Gateway 浏览器会话功能未启用
401 OIDC_SESSION_INVALID Session 不存在、Cookie 格式错误或 Token 身份不匹配
401 OIDC_SESSION_EXPIRED 闲置/绝对期限已到或 Refresh Token 已失效
503 OIDC_SESSION_REFRESH_UNAVAILABLE Access Token 已过期且认证中心暂时不可用
503 OIDC_SESSION_STORE_UNAVAILABLE 数据库或 Token 密文不可用
403 OIDC_SESSION_CSRF_REJECTED Cookie 写请求缺少可信 Origin

ErrLocalUserRequired 仅作为防御性内部错误保留,对外统一转换为结构化 403。

验收与回滚

自动化门禁通过后,依次验证本地真实 OIDC 和 auth.51easyai.com Staging 专用测试租户。证据应包含脱敏 Claims、网络截图、本地 Gateway 用户记录、Trace ID、Gateway/Auth Center 审计 ID及 200/401/403/503 负向证据;不得保存 Token、授权码、密码或 Secret。

JIT 回滚时关闭 OIDC_JIT_PROVISIONING_ENABLED 并回退 Gateway 镜像。浏览器 Cookie 会话可通过后端和 Web 两侧的独立开关关闭。已经创建的 source=oidc 测试投影保留为惰性数据,不自动删除、迁移或合并。