浏览器只通过 HttpOnly Cookie 恢复统一认证状态,不再访问认证中心 Token Endpoint 或保存 OIDC Token。同步更新错误提示、部署配置和接入文档。
74 lines
5.9 KiB
Markdown
74 lines
5.9 KiB
Markdown
# 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 不能创建租户。
|
||
|
||
## 配置
|
||
|
||
```dotenv
|
||
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 小时。闲置 5~30 分钟后的首个请求可自动刷新;超过闲置或绝对期限不会刷新,必须重新登录。浏览器不运行定时刷新。
|
||
- 所有 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=sub`;`user_key` 由规范化 Issuer 和 `sub` 做 SHA-256 派生,不按邮箱、手机号、昵称匹配。
|
||
- 首次登录在一个事务中创建 `gateway_users` 投影、绑定租户默认用户组、初始化 `resource` 钱包并写入 `identity.oidc_user.provisioned` 审计事件。
|
||
- 重复或并发登录依赖现有唯一约束和冲突处理返回同一个本地用户,不重复创建钱包或首次预配审计。
|
||
- 后续登录只同步 Token 用户名、应用角色、`last_login_at`、`synced_at` 和 `source_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` 测试投影保留为惰性数据,不自动删除、迁移或合并。
|