forked from wangziqi/gongxue-base
docs: clarify supabase frontend access strategy
This commit is contained in:
161
docs/refactor/supabase-frontend-access-strategy.md
Normal file
161
docs/refactor/supabase-frontend-access-strategy.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# Supabase 前端访问策略
|
||||
|
||||
更新时间:2026-06-28
|
||||
|
||||
这份文档用于回答一个关键架构问题:Taro/H5/小程序前端到底应该直接调用 Supabase,还是调用我们自己的 `apps/api` 后端?
|
||||
|
||||
结论:采用“Supabase Auth/JWT + 业务 API 优先 + 有边界的 Supabase Client 直连”的混合架构。
|
||||
|
||||
## 官方依据
|
||||
|
||||
Supabase 官方文档的核心原则:
|
||||
|
||||
- 前端可以使用 Supabase client/Data API 访问数据,但前提是启用 RLS,并且只授予最小权限。
|
||||
- https://supabase.com/docs/guides/database/secure-data
|
||||
- https://supabase.com/docs/guides/database/postgres/row-level-security
|
||||
- 前端应使用 publishable key;publishable key 可以暴露,但必须配合 RLS 和最小权限。
|
||||
- https://supabase.com/docs/guides/database/secure-data
|
||||
- https://supabase.com/docs/guides/getting-started/api-keys
|
||||
- secret key / service role key 永远不能暴露在前端,因为它们会绕过 RLS。
|
||||
- https://supabase.com/docs/guides/getting-started/api-keys
|
||||
- 复杂服务端逻辑、第三方 API、webhook、密钥和数据库连接应放在服务端,例如 Edge Functions、worker 或自有后端。
|
||||
- https://supabase.com/docs/guides/functions
|
||||
- Supabase Auth 使用 JWT,JWT 可以和 RLS、服务端鉴权结合。
|
||||
- https://supabase.com/docs/guides/auth
|
||||
- https://supabase.com/docs/guides/auth/jwts
|
||||
|
||||
## 对本项目的判断
|
||||
|
||||
我们的系统不是简单 CRUD 应用,而是面向同行销售的题库 SaaS:
|
||||
|
||||
- 多租户隔离。
|
||||
- 平台超级管理员和租户管理员双后台。
|
||||
- 租户内自定义角色、运营、教师、销售、代理、学生。
|
||||
- 订单、支付、激活码、权益、视频次数。
|
||||
- 题库导入、内容审核、资源台账。
|
||||
- 阿里云 OSS、腾讯 COS、Supabase Storage 混合对象存储。
|
||||
- CRM 推送、销售首绑、分佣结算。
|
||||
- 未来还要接微信/QQ 登录、微信/支付宝支付、AI 报告。
|
||||
|
||||
这些都包含复杂业务规则、密钥、幂等、审计和跨表事务。因此不能让 Taro 前端直接写业务表来替代后端。
|
||||
|
||||
## 推荐架构
|
||||
|
||||
```text
|
||||
Taro/H5/小程序
|
||||
├─ Supabase client
|
||||
│ ├─ Auth session/JWT
|
||||
│ ├─ 可选:Realtime
|
||||
│ └─ 可选:严格 RLS 下的低风险只读数据
|
||||
│
|
||||
└─ apps/api 业务 API
|
||||
├─ 校验 Supabase JWT/session
|
||||
├─ 解析 tenant
|
||||
├─ 校验角色和 permissions
|
||||
├─ 执行业务事务
|
||||
├─ 写审计日志
|
||||
├─ 签发对象存储 URL
|
||||
└─ 调用支付/短信/微信/QQ/CRM/AI provider
|
||||
```
|
||||
|
||||
`apps/api` 可以部署为我们自己的 Node.js API,也可以在部分云原生场景下拆为 Supabase Edge Functions。对当前项目而言,保留 `apps/api` 更适合复杂业务、国内 provider、自托管和后续 worker。
|
||||
|
||||
## 前端直连 Supabase 的适用范围
|
||||
|
||||
| 能力 | 是否建议前端直连 Supabase | 说明 |
|
||||
| --- | --- | --- |
|
||||
| Supabase Auth session | 建议 | H5 可直接用 `@supabase/supabase-js`;小程序需先验证运行时兼容性 |
|
||||
| 获取当前用户 JWT | 建议 | API 请求统一带 `Authorization: Bearer <access_token>` |
|
||||
| 低风险公开只读数据 | 可选 | 仅限 RLS、grant、索引都成熟后;当前默认仍走 `apps/api` |
|
||||
| Realtime 通知 | 可选 | 非敏感通知、学习状态刷新可考虑;后台敏感队列不建议前端订阅 |
|
||||
| Public Storage 公开资源 | 可选 | 真正公开的 Logo、主题图可直连 CDN/公开 bucket |
|
||||
| 私有资料/PDF/视频 | 不建议 | 必须通过 `content_assets` 权限校验和后端签名 |
|
||||
| 学习记录/答题/错题/收藏 | 不建议 | 涉及权益、统计、审计、题目快照,应走 API |
|
||||
| 订单/支付/激活码/优惠券 | 禁止 | 必须走后端事务、验签和幂等 |
|
||||
| 租户后台配置 | 禁止 | 涉及权限、密钥、审计 |
|
||||
| 内容导入/题库维护 | 禁止 | 必须走 preview/import/job/issues 管线 |
|
||||
| 平台超级后台 | 禁止 | 必须走平台管理员鉴权和审计 |
|
||||
|
||||
## Taro 运行时建议
|
||||
|
||||
Taro 要同时支持 H5 和微信小程序。Supabase 官方 JavaScript client 是通用 JS SDK,并提供 browser、React Native、自定义 fetch/storage 等配置方式,但微信小程序环境不等同于标准浏览器。
|
||||
|
||||
因此建议:
|
||||
|
||||
1. H5 端优先使用 `@supabase/supabase-js` 管理 Auth session。
|
||||
2. 微信小程序端先做兼容性验证:
|
||||
- `fetch` 或 request adapter。
|
||||
- storage adapter。
|
||||
- URL polyfill。
|
||||
- token auto refresh。
|
||||
3. 如果小程序端 `supabase-js` 兼容成本高,则小程序只调用 `apps/api/auth/*`:
|
||||
- 前端把微信 `code` 或手机号验证码发给后端。
|
||||
- 后端调用 Supabase Auth/Admin 或自有 session 逻辑换取可信 session。
|
||||
- 前端保存后端返回的 access token/session。
|
||||
4. 无论 H5 还是小程序,业务数据默认调用 `apps/api`,不直接写 Supabase 表。
|
||||
|
||||
## 推荐前端环境变量
|
||||
|
||||
只允许出现在前端构建中的变量:
|
||||
|
||||
```text
|
||||
TARO_APP_API_BASE_URL=https://api.example.com
|
||||
TARO_APP_SUPABASE_URL=https://<project-ref>.supabase.co
|
||||
TARO_APP_SUPABASE_PUBLISHABLE_KEY=sb_publishable_xxx
|
||||
```
|
||||
|
||||
禁止出现在前端:
|
||||
|
||||
```text
|
||||
SUPABASE_SECRET_KEY
|
||||
SUPABASE_SERVICE_ROLE_KEY
|
||||
DATABASE_URL
|
||||
ALIYUN_OSS_ACCESS_KEY_SECRET
|
||||
TENCENT_COS_SECRET_KEY
|
||||
WECHAT_PAY_PRIVATE_KEY
|
||||
ALIPAY_APP_PRIVATE_KEY
|
||||
AUTH_SESSION_SECRET
|
||||
PLATFORM_ADMIN_API_KEY
|
||||
```
|
||||
|
||||
## API 请求目标形态
|
||||
|
||||
当前迁移期:
|
||||
|
||||
```text
|
||||
Authorization: Bearer <tk_session>
|
||||
x-tenant-id: <tenantId>
|
||||
x-user-id: <userId>
|
||||
```
|
||||
|
||||
生产目标:
|
||||
|
||||
```text
|
||||
Authorization: Bearer <supabase_access_token_or_server_session>
|
||||
```
|
||||
|
||||
生产时后端负责:
|
||||
|
||||
- 验证 JWT。
|
||||
- 从 JWT/session 获取 userId。
|
||||
- 根据 host/tenantCode/JWT claims 解析 tenant。
|
||||
- 校验用户属于该租户。
|
||||
- 校验角色和权限。
|
||||
- 执行业务逻辑。
|
||||
|
||||
前端不再传 `x-user-id`,也不能靠传 `tenantId` 获得跨租户数据。
|
||||
|
||||
## 对后续 AI/开发者的硬性约束
|
||||
|
||||
- 不要把 `apps/api` 删除或绕过。
|
||||
- 不要让 Taro 直接写订单、支付、权益、内容、租户配置、CRM、导入相关表。
|
||||
- 不要把 service role/secret key 放进 Taro。
|
||||
- 不要为了少写接口而放宽 RLS。
|
||||
- 新增前端直连 Supabase 表之前,必须先补:
|
||||
- 明确 RLS policy。
|
||||
- 最小 grant。
|
||||
- 跨租户测试。
|
||||
- 权限测试。
|
||||
- 性能索引。
|
||||
- 若某个功能需要密钥、跨表事务、webhook、审计、幂等或第三方 provider,一律放到 `apps/api` 或 worker/Edge Function。
|
||||
|
||||
Reference in New Issue
Block a user