forked from wangziqi/gongxue-base
feat: prefer supabase jwt in taro api client
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
- `practice_blueprints`
|
||||
- 可以接入迁移期短信登录和 `tk_` session,用于本地/内网联调。
|
||||
- H5 可以直接用 Supabase Auth access token 调 `apps/api`;后端已支持 JWT 验签和业务用户映射。
|
||||
- `apps/taro/src/services/api.ts` 现在默认 Supabase JWT 优先、迁移期 `tk_` 兜底;公共接口必须显式 `authMode='none'`。页面不要手写 `Authorization`、`x-tenant-id` 或 `x-user-id`。
|
||||
- H5 可以优先验证 `@supabase/supabase-js` 管理 Auth session;微信小程序端先验证运行时兼容性,业务数据默认仍走 `apps/api`。
|
||||
- H5 生产部署优先用每个静态目录自己的 `runtime-config.json` 配置 `apiBaseUrl`、`supabaseUrl`、`supabasePublishableKey`、`tenantCode`;不要为了换域名重打包,也不要把任何 service role、数据库、支付、短信、对象存储密钥放进该文件。
|
||||
- 可以接入租户品牌、已发布主题、公开素材、功能开关和域名/小程序参数解析;学生端只读 `/api/tenant/resolve` 的 `branding.theme/publicAssets`,租户后台草稿走 `/api/tenant-admin/theme`。
|
||||
|
||||
@@ -139,7 +139,7 @@ PLATFORM_ADMIN_API_KEY
|
||||
|
||||
## API 请求目标形态
|
||||
|
||||
当前迁移期:
|
||||
历史迁移期接口曾允许:
|
||||
|
||||
```text
|
||||
Authorization: Bearer <tk_session>
|
||||
@@ -147,13 +147,15 @@ x-tenant-id: <tenantId>
|
||||
x-user-id: <userId>
|
||||
```
|
||||
|
||||
生产目标:
|
||||
新的 Taro client 已经禁止页面使用 `x-user-id` 表示当前用户,并默认采用 Supabase JWT 优先:
|
||||
|
||||
```text
|
||||
Authorization: Bearer <supabase_access_token>
|
||||
x-tenant-id: <tenantId> # 可选租户上下文;不是身份来源,必须与 JWT tenant claim 或 membership 匹配
|
||||
```
|
||||
|
||||
`apps/taro/src/services/api.ts` 的 `apiRequest` 默认 `authMode='auto'`:H5 优先发送 Supabase access token,没有 Supabase token 时才兜底迁移期 `tk_` session。公共接口必须显式使用 `authMode='none'`,迁移演练才允许使用 `authMode='legacy'`,云端正式回归可用 `authMode='supabase'` 强制暴露残留 legacy 依赖。`headers.Authorization` 和 `headers['x-tenant-id']` 是保留 header,页面代码不能覆盖。
|
||||
|
||||
当前 `apps/api` 已支持 Supabase Auth JWT 验签,并通过 `auth.users.id -> platform_users.auth_user_id -> tenant_memberships` 映射到业务身份。H5/Taro 登录后可以直接把 Supabase access token 放到 `Authorization`。如果 JWT 内没有 `tenant_id` claim,前端仍要根据域名/小程序码解析后的租户传 `x-tenant-id`,后端会校验该用户确实属于该租户。
|
||||
|
||||
生产时后端负责:
|
||||
@@ -183,6 +185,7 @@ ALLOW_PLATFORM_ADMIN_KEY=false
|
||||
- 不要把 Supabase-first 误解成前端直写所有表。
|
||||
- 不要让 Taro 直接写订单、支付、权益、租户配置、CRM、导入相关表。
|
||||
- 不要把 service role/secret key 放进 Taro。
|
||||
- 不要在页面里绕过 `apiRequest` 手写 `Taro.request`、`Authorization`、`x-tenant-id` 或 `x-user-id`。
|
||||
- 不要为了少写接口而放宽 RLS。
|
||||
- 新增前端直连 Supabase table/view/RPC 之前,必须先补:
|
||||
- 明确 RLS policy。
|
||||
|
||||
@@ -53,7 +53,23 @@ F:\project\参考\旧题库项目\src
|
||||
- 私有 PDF、资料、视频、对象存储签名。
|
||||
- 租户后台、平台后台、内容导入、CRM、销售/代理、数据看板。
|
||||
|
||||
前端应封装一个统一 API client,所有页面禁止直接散写 `Taro.request`。
|
||||
前端应封装一个统一 API client,所有页面禁止直接散写 `Taro.request`。当前统一入口是:
|
||||
|
||||
```text
|
||||
apps/taro/src/services/api.ts
|
||||
apps/taro/src/services/api-auth.ts
|
||||
```
|
||||
|
||||
`apiRequest` 的默认鉴权模式是 `authMode='auto'`:
|
||||
|
||||
| authMode | 行为 | 适用场景 |
|
||||
| --- | --- | --- |
|
||||
| `auto` | H5 先读取 Supabase Auth access token;没有 Supabase token 时才兜底迁移期 `tk_` session | 绝大多数登录后业务接口 |
|
||||
| `supabase` | 只发送 Supabase access token,没有 token 也不回退 `tk_` | 云端 JWT/RLS 回归、需要提前发现迁移 token 依赖的页面 |
|
||||
| `legacy` | 只发送迁移期 `tk_` session | 本地迁移、旧数据导入演练、临时内网联调 |
|
||||
| `none` | 不发送 Authorization | 租户解析、短信发送/验证、公开目录、公开套餐等接口 |
|
||||
|
||||
公共接口必须显式传 `authMode: 'none'`,例如 `tenant/resolve`、`catalog/regions`、`catalog/content-entries`、`catalog/svip-plans`、`auth/sms/send`。平台全局接口或租户解析如不应带租户上下文,必须显式传 `tenantId: null`;不能依赖当前本地缓存的租户。
|
||||
|
||||
本地迁移期仍可兼容旧请求头,但新的 Taro 请求封装必须按下面目标实现:
|
||||
|
||||
@@ -71,20 +87,14 @@ x-tenant-id: <tenantId> # 作为租户上下文,不能作为身份依据
|
||||
|
||||
前端不应再传 `x-user-id`、query/body `userId` 来表示当前用户。后端已经实现 Supabase JWT 和迁移 session 优先解析:如果 Authorization 存在,用户态接口以 token 映射出的业务用户为准;如果请求里伪造了不同的 `userId` 会返回 `AUTH_USER_MISMATCH`,伪造不同租户会返回 `AUTH_TENANT_MISMATCH` 或 `AUTH_SESSION_INVALID`。
|
||||
|
||||
H5 使用 Supabase Auth 时,推荐请求流程:
|
||||
H5 使用 Supabase Auth 时,不要在页面里手写 `Authorization`,推荐请求流程是由统一 client 完成:
|
||||
|
||||
```ts
|
||||
const { data } = await supabase.auth.getSession();
|
||||
const accessToken = data.session?.access_token;
|
||||
|
||||
await api.request('/api/profile/me', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'x-tenant-id': tenantStore.tenantId,
|
||||
},
|
||||
});
|
||||
await apiRequest('/api/profile/me');
|
||||
```
|
||||
|
||||
`apps/taro/src/services/api-auth.ts` 会读取 Supabase session 并生成 `Authorization: Bearer <supabase_access_token>`。页面层禁止通过 `headers.Authorization` 或 `headers['x-tenant-id']` 覆盖身份和租户上下文;如确实要切换租户上下文,必须使用 `tenantId` 显式参数。该规则由 `scripts/taro-api-auth-mode-test.js` 纳入 `npm run test:readiness`。
|
||||
|
||||
后端会通过 `auth.users.id -> platform_users.auth_user_id -> tenant_memberships` 映射用户身份。`x-tenant-id` 只能帮助确定当前租户上下文,不能让用户访问自己没有 membership 的租户。
|
||||
|
||||
生产或云端测试建议设置:
|
||||
|
||||
@@ -146,10 +146,15 @@ ALLOW_LEGACY_AUTH_HEADERS=false
|
||||
ALLOW_PLATFORM_ADMIN_KEY=false
|
||||
```
|
||||
|
||||
H5 正式回归时建议把前端登录态切到 Supabase Auth,并观察业务接口请求是否都发送 `Bearer <supabase_access_token>`。`tk_` session 只作为迁移/本地兜底,不应成为线上长期依赖。
|
||||
|
||||
## 前端请求边界
|
||||
|
||||
- 所有页面统一通过 `apps/taro/src/services/api.ts` 调用后端。
|
||||
- 默认请求模式是 `authMode='auto'`:H5 先用 Supabase JWT,没有 JWT 才兜底迁移期 `tk_` session。
|
||||
- 公共接口、短信登录、租户解析必须显式 `authMode='none'`;平台全局或租户解析不应带租户上下文时必须显式 `tenantId: null`。
|
||||
- H5 可以用 Supabase client 管理 Auth session/JWT,但业务数据默认走 `apps/api`。
|
||||
- 页面代码不能通过 `headers` 覆盖 `Authorization` 或 `x-tenant-id`,身份和租户上下文只能走统一 client 的 token provider、`authMode` 和 `tenantId` 参数。
|
||||
- 订单、支付、权益、内容导入、后台配置、CRM、对象存储签名、视频播放签名必须走后端命令层。
|
||||
- 登录后禁止传 `x-user-id` 或 body/query `userId` 表示当前用户。
|
||||
- 私有 PDF、图片、视频不能由前端拼接 URL,必须使用 `content_assets` 和后端短签名。
|
||||
|
||||
Reference in New Issue
Block a user