Files
gongxue-base/docs/refactor/multitenant-auth-security-contract.md
2026-06-28 20:37:53 +08:00

5.2 KiB
Raw Blame History

多租户与鉴权安全契约

更新时间2026-06-28

这个系统后续要卖给同行作为题库 SaaS因此租户隔离、鉴权、资源权限和审计是商用红线。前端可以先按迁移期接口联调但正式上云验收前必须完成本文件的 P0 项。

安全边界

边界 规则
平台超级管理员 可管理全部租户、SaaS 套餐、订阅、账单、用量、公共题库
租户管理员 只能管理自己租户的品牌、域名、成员、内容、营销、订单和 CRM
租户成员 按角色和 permissions 访问,例如运营、教师、销售、代理
学生用户 只能访问自己所在租户下被授权的内容和自己的学习数据
公共题库 必须通过平台授权/租户采纳后才对租户可见
私有资源 必须通过后端权限校验后签名访问,不能前端直连对象存储

当前迁移期状态

当前后端仍存在这些迁移期实现:

  • x-tenant-id 用于租户上下文。
  • x-user-id 或 body/query 的 userId 用于用户上下文。
  • x-platform-admin-key 用于平台管理员接口。
  • 本地短信 provider 可使用 mock
  • 默认开发密钥存在于 .env.example 和 config fallback。

这些只允许用于本地开发和内网联调,不允许作为正式云端验收方案。

P0正式云端测试前必须完成

  1. 正式用户鉴权

    • 使用 Supabase Auth/JWT 或服务端 session 解析可信 userId。
    • 禁止前端通过 query/body/header 指定 userId。
    • GET /api/auth/me 返回当前用户、租户成员、角色、权限。
  2. 正式租户上下文

    • H5 可由域名解析租户。
    • 小程序可由 tenantCode 解析租户。
    • 后端必须校验用户是否属于该租户。
    • 跨租户请求必须返回 403 或 404。
  3. 平台管理员鉴权

    • 替换 x-platform-admin-key
    • 平台管理员也要有 JWT/session、角色、审计日志。
  4. 生产配置 fail-fast

    • NODE_ENV=production 时禁止默认 AUTH_CODE_PEPPER
    • 禁止默认 AUTH_SESSION_SECRET
    • 禁止默认 PLATFORM_ADMIN_API_KEY
    • 禁止 CORS_ORIGIN=*
    • 禁止 AUTH_SMS_PROVIDER=mock
  5. 请求体大小限制

    • 普通 JSON API 必须有默认上限。
    • 导入接口可以有更大上限,但必须可配置且有最大值。
    • 超限返回 413。
  6. 租户密钥保护

    • 商户密钥、短信 secret、OAuth secret 不允许明文长期存储。
    • 生产应使用 KMS/Vault 或 envelope encryption。
    • API 只返回 secretRef、掩码和配置状态。
  7. RLS 与 API 双层回归

    • 数据库 RLS 要按 tenant_id 拦截。
    • API SQL 必须显式带 tenant_id
    • 测试必须覆盖跨租户读取、写入、下载、后台权限越权。

前端必须遵守

  • 不信任本地缓存里的 tenantId/userId 作为安全依据。
  • 不在页面里保存或展示任何商户密钥、短信密钥、OAuth secret。
  • 不在前端硬编码对象存储 bucket、私有资源路径、商户号。
  • 不在前端自行开通会员权益;必须通过订单/支付/激活码后端流程。
  • 不允许“切换销售归属”这类破坏首绑保护的入口,除非后端提供带权限的管理接口。
  • 不在前端直接判断“这个用户能不能看某题/某视频/某资料”的最终结果;必须请求后端。
  • 切换租户、退出登录、登录新账号时,清理旧租户缓存和用户缓存。

后端接口约定

所有业务表查询必须满足:

where tenant_id = currentTenantId

管理类写接口必须满足:

requireTenantPermission(auth, '<scope>:<action>')

平台类接口必须满足:

requirePlatformAdmin(auth)

资源下载必须满足:

content_assets 台账存在
资源属于当前 tenant
资源状态允许访问
用户权益满足 visibility/access_rules
返回短期签名 URL

支付 webhook 必须满足:

验签通过
provider event id 幂等
订单 tenant_id 匹配
金额以后端订单金额为准
事务内更新 payment/order/entitlement
记录 payment_events

权限点现状

当前默认角色:

角色 默认权限
tenant_owner *
tenant_admin *
tenant_operator 内容、营销、兑换码/优惠券只读、客资/CRM 只读
teacher 内容维护
sales 兑换码、优惠券、客资
agent 兑换码/优惠券只读、本人的客资
student 无后台权限

后续要补:

  • 租户自定义角色模板。
  • 菜单级、模块级、字段级权限。
  • 权限变更审计。
  • 班级/教师/学生范围权限。

上线前安全验收清单

  • npm audit 为 0 高危/严重漏洞。
  • npm run check:refactor 通过。
  • 生产环境启动时默认密钥 fail-fast 生效。
  • 跨租户学生读取题目/订单/资料返回拒绝。
  • 销售只能查看自己权限范围内客资。
  • 代理不能查看其他代理客资。
  • 教师不能修改租户商户密钥。
  • 学生不能访问租户后台接口。
  • 未开通权益不能下载 SVIP 资料或播放会员视频。
  • 支付 webhook 重放不会重复开通权益。
  • 激活码并发兑换只能成功一次。
  • 对象存储签名 URL 有短 TTL。
  • 后台关键操作写入 audit log。