forked from wangziqi/gongxue-base
feat: enforce trusted session identity
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
| 模块 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| Supabase/PostgreSQL schema | 可联调 | `supabase/migrations` 已包含多租户、题库、学习、订单、内容、CRM、平台账务等表 |
|
||||
| RLS/租户隔离 | 迁移期 | 表层普遍有 `tenant_id` 和 RLS 策略,但 API 目前使用服务端连接,生产前要补真实 JWT/RLS 回归 |
|
||||
| RLS/租户隔离 | 迁移期 | 表层普遍有 `tenant_id` 和 RLS 策略,API 已接入 session 优先身份上下文;生产前继续补 Supabase JWT/RLS 回归 |
|
||||
| API 分层 | 可联调 | `apps/api/src/core` + `apps/api/src/features/*` |
|
||||
| Docker API | 可联调 | `docker-compose.api.yml` 和 `apps/api/Dockerfile` 可用 |
|
||||
| 测试 | 可联调 | `npm run check:refactor` 覆盖 TS 检查、导入校验、seed、API 集成测试 |
|
||||
@@ -36,9 +36,9 @@
|
||||
| 能力 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 短信验证码登录 | 迁移期 | 已有验证码、冷却、hash、登录事件;mock provider 可本地联调 |
|
||||
| 迁移期 session | 迁移期 | `tk_` token hash 存在 `app_private.auth_sessions` |
|
||||
| 迁移期 session | 迁移期 | `tk_` token hash 存在 `app_private.auth_sessions`,用户态接口已优先解析 bearer session 并拒绝伪造 userId/tenantId |
|
||||
| 微信/QQ OAuth | 待补齐 | 目前是 placeholder |
|
||||
| 平台管理员鉴权 | 迁移期 | 当前用 `x-platform-admin-key`,生产前必须换 JWT/服务端会话 |
|
||||
| 平台管理员鉴权 | 迁移期 | `x-platform-admin-key` 已可通过配置禁用;生产前必须换平台管理员 JWT/服务端会话 |
|
||||
| 租户角色权限 | 可联调 | `tenant_memberships.role + permissions`,接口有权限点校验 |
|
||||
| 自定义角色模板 | 待补齐 | 当前有权限 JSON 覆盖,缺角色模板、菜单/模块/字段级权限配置 UI/API |
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
|
||||
## 当前验证
|
||||
|
||||
最近已通过:
|
||||
最近需通过:
|
||||
|
||||
```bash
|
||||
npm audit
|
||||
@@ -153,4 +153,3 @@ npm run check:refactor
|
||||
- smoke seed
|
||||
- API build
|
||||
- API integration tests
|
||||
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
|
||||
## 当前迁移期状态
|
||||
|
||||
当前后端仍存在这些迁移期实现:
|
||||
当前后端已经进入“session 优先、迁移头受控兼容”的状态:
|
||||
|
||||
- `x-tenant-id` 用于租户上下文。
|
||||
- `x-user-id` 或 body/query 的 `userId` 用于用户上下文。
|
||||
- `x-platform-admin-key` 用于平台管理员接口。
|
||||
- `Authorization: Bearer <tk_session>` 会优先解析 `app_private.auth_sessions`,并作为用户身份来源。
|
||||
- 登录后如果请求中的 `x-user-id`、query/body `userId` 与 session 用户不一致,后端返回 `AUTH_USER_MISMATCH`。
|
||||
- 登录后如果请求中的 `x-tenant-id` 与 session 租户不一致,后端返回 `AUTH_TENANT_MISMATCH`。
|
||||
- 带了无效 bearer token 的用户态接口不会回退到 `x-user-id`。
|
||||
- `x-user-id` 或 body/query 的 `userId` 只允许在 `ALLOW_LEGACY_AUTH_HEADERS=true` 的本地/迁移期环境使用。
|
||||
- `x-platform-admin-key` 只允许在 `ALLOW_PLATFORM_ADMIN_KEY=true` 的本地/迁移期环境使用。
|
||||
- 本地短信 provider 可使用 `mock`。
|
||||
- 默认开发密钥存在于 `.env.example` 和 config fallback。
|
||||
- `NODE_ENV=production` 下禁止 `ALLOW_LEGACY_AUTH_HEADERS=true`、`ALLOW_PLATFORM_ADMIN_KEY=true`、`AUTH_SMS_PROVIDER=mock`、默认/弱密钥和 `CORS_ORIGIN=*`。
|
||||
|
||||
这些只允许用于本地开发和内网联调,不允许作为正式云端验收方案。
|
||||
|
||||
@@ -32,9 +35,10 @@ Supabase 官方允许前端用 Data API 访问数据,但前提是 RLS、最小
|
||||
## P0:正式云端测试前必须完成
|
||||
|
||||
1. 正式用户鉴权
|
||||
- 使用 Supabase Auth/JWT 或服务端 session 解析可信 userId。
|
||||
- 禁止前端通过 query/body/header 指定 userId。
|
||||
- `GET /api/auth/me` 返回当前用户、租户成员、角色、权限。
|
||||
- 已支持服务端 session 解析可信 userId。
|
||||
- 生产前继续接 Supabase Auth/JWT,或将现有 server session 明确作为正式方案。
|
||||
- 前端禁止通过 query/body/header 指定 userId。
|
||||
- `GET /api/auth/me` 后续要补租户成员、角色、权限返回。
|
||||
|
||||
2. 正式租户上下文
|
||||
- H5 可由域名解析租户。
|
||||
@@ -43,7 +47,8 @@ Supabase 官方允许前端用 Data API 访问数据,但前提是 RLS、最小
|
||||
- 跨租户请求必须返回 403 或 404。
|
||||
|
||||
3. 平台管理员鉴权
|
||||
- 替换 `x-platform-admin-key`。
|
||||
- `x-platform-admin-key` 已可通过 `ALLOW_PLATFORM_ADMIN_KEY=false` 禁用。
|
||||
- 生产前仍需替换为平台管理员 JWT/session 和审计日志。
|
||||
- 平台管理员也要有 JWT/session、角色、审计日志。
|
||||
|
||||
4. 生产配置 fail-fast
|
||||
@@ -52,6 +57,8 @@ Supabase 官方允许前端用 Data API 访问数据,但前提是 RLS、最小
|
||||
- 禁止默认 `PLATFORM_ADMIN_API_KEY`。
|
||||
- 禁止 `CORS_ORIGIN=*`。
|
||||
- 禁止 `AUTH_SMS_PROVIDER=mock`。
|
||||
- 禁止 `ALLOW_LEGACY_AUTH_HEADERS=true`。
|
||||
- 禁止 `ALLOW_PLATFORM_ADMIN_KEY=true`。
|
||||
|
||||
5. 请求体大小限制
|
||||
- 普通 JSON API 必须有默认上限。
|
||||
|
||||
@@ -55,12 +55,11 @@ F:\project\参考\旧题库项目\src
|
||||
|
||||
前端应封装一个统一 API client,所有页面禁止直接散写 `Taro.request`。
|
||||
|
||||
迁移期请求头:
|
||||
本地迁移期仍可兼容旧请求头,但新的 Taro 请求封装必须按下面目标实现:
|
||||
|
||||
```text
|
||||
Authorization: Bearer <tk_session>
|
||||
x-tenant-id: <tenantId>
|
||||
x-user-id: <userId>
|
||||
x-tenant-id: <tenantId> # 仅作为登录前/公开目录租户上下文;登录后必须与 session 租户一致
|
||||
```
|
||||
|
||||
生产目标:
|
||||
@@ -69,7 +68,16 @@ x-user-id: <userId>
|
||||
Authorization: Bearer <supabase_access_token_or_server_session>
|
||||
```
|
||||
|
||||
生产后不应再由前端传 `x-user-id`。租户可以由可信 JWT claim、服务端 session、域名解析结果共同确定;前端传入的租户参数只能作为路由/展示上下文,不能作为安全依据。
|
||||
前端不应再传 `x-user-id`、query/body `userId` 来表示当前用户。后端已经实现 session 优先解析:如果 Authorization 存在,用户态接口以 session 用户为准;如果请求里伪造了不同的 `userId` 会返回 `AUTH_USER_MISMATCH`,伪造不同租户会返回 `AUTH_TENANT_MISMATCH`。
|
||||
|
||||
生产或云端测试建议设置:
|
||||
|
||||
```text
|
||||
ALLOW_LEGACY_AUTH_HEADERS=false
|
||||
ALLOW_PLATFORM_ADMIN_KEY=false
|
||||
```
|
||||
|
||||
这样旧式 `x-user-id` 和平台管理 key 会被拒绝,前端可以提前发现未按 session 接入的页面。
|
||||
|
||||
前端环境变量只允许包含:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user