feat: 将 Gateway Web 迁移到 BFF 会话

浏览器只通过 HttpOnly Cookie 恢复统一认证状态,不再访问认证中心 Token Endpoint 或保存 OIDC Token。同步更新错误提示、部署配置和接入文档。
This commit is contained in:
2026-07-13 19:09:57 +08:00
parent c5c82bb528
commit 46bac51703
15 changed files with 143 additions and 287 deletions
+18 -8
View File
@@ -14,6 +14,13 @@ 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` 映射仍会解析和同步登录时间。
@@ -22,14 +29,15 @@ OIDC_SESSION_COOKIE_SECURE=false # 本地 HTTP;生产必须为 true
## Web Console 浏览器会话
- OIDC 回调仍使用 Authorization Code + PKCE 从 Auth Center 获取 Access Token,但 Token 只在回调函数内存中短暂存在
- Web 随即调用 `POST /api/v1/auth/oidc/session`Gateway 再次完成全部 OIDC 校验后,将原 Auth Center Access Token 写入 `HttpOnly + SameSite=Strict` Cookie,不签发第二枚 Gateway JWT
- Cookie 有效期不超过 Access Token 的 `exp`,所有 Cookie 请求仍经过 JWKS、Issuer、Audience、`tid`、Scope、角色及可选 Introspection 校验
- 建立成功后清除旧的 OIDC `sessionStorage` 和可能冲突的 `localStorage` Token;新标签页通过 Cookie 调用 `/api/v1/me` 自动恢复同一登录态
- 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`
- `DELETE /api/v1/auth/oidc/session` 使 Cookie 立即过期,然后前端进入 Auth Center OIDC 登出。浏览器会话关闭时不会创建或撤销 Gateway API Key
- 回滚时同时设置后端 `OIDC_BROWSER_SESSION_ENABLED=false` 和 Web 构建参数 `VITE_OIDC_BROWSER_SESSION_ENABLED=false`,恢复旧的标签页级 `sessionStorage` 行为
- `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` 可停止新会话;回滚镜像后已创建记录作为惰性数据保留
## 数据和事务语义
@@ -50,8 +58,10 @@ OIDC_SESSION_COOKIE_SECURE=false # 本地 HTTP;生产必须为 true
| 503 | `GATEWAY_TENANT_UNAVAILABLE` | 配置租户或用户组不存在/未启用 |
| 503 | `GATEWAY_USER_PROVISIONING_FAILED` | 事务或存储故障;响应不暴露内部错误 |
| 404 | `OIDC_BROWSER_SESSION_DISABLED` | Gateway 浏览器会话功能未启用 |
| 401 | `OIDC_SESSION_INVALID` | 不是有效的 Auth Center OIDC Access Token 或已过期 |
| 400 | `OIDC_SESSION_TOKEN_TOO_LARGE` | Access Token 超过安全 Cookie 大小限制 |
| 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。