uniCloud本身不内置多租户能力,所有租户隔离必须由开发者显式实现:查询、写入、聚合均需硬编码tenant_id;云函数须从uniIdToken安全解析并校验租户;数据库索引须含tenant_id复合字段;云存储路径须带tenant_id前缀;函数间调用须逐层透传与校验。

uniCloud 本身不内置多租户能力,所有租户隔离逻辑必须由开发者显式实现。直接依赖 uniCloud.callFunction 或 db.collection 默认行为,必然导致数据串扰。
tenant_id 必须作为查询条件硬编码进每条数据库操作
uniCloud 的云函数和数据库 API 不会自动注入租户上下文。你不能指望「登录态」或「请求头」自动过滤数据 —— 它们根本不会被数据库层识别。
- 所有
db.collection('orders').where()查询,必须显式加上{ tenant_id: $tenantId } - 写入时也必须手动赋值:
{ tenant_id: $tenantId, ...data },不能依赖前端传入的tenant_id字段(可能被篡改) - 聚合查询(
aggregate)同样要加$match: { tenant_id: $tenantId },否则跨租户统计会出错 - 云函数入口需从
event中安全提取租户标识:优先用event.uniIdToken解析出用户所属租户,而非信任event.tenant_id参数
云函数入口统一校验租户上下文,拒绝非法请求
绕过前端控制是常见攻击路径。比如用户修改 URL 参数或重放请求,直接调用本不该访问的租户接口。
- 在每个云函数开头,用
uniCloud.getJWTPayload(event.uniIdToken)解析 token,从中取出真实tenant_id - 若解析失败、token 过期、或解析出的
tenant_id与请求参数不一致,立即throw new Error('Invalid tenant context') - 不要只做「存在性判断」,例如
if (!event.tenant_id) return—— 这等于放行所有未带参数的请求,风险极高
数据库索引必须包含 tenant_id,否则查询性能崩塌
当集合数据量超过万级,没加 tenant_id 的复合索引,会导致全表扫描。uniCloud 控制台里查慢日志,90% 的超时都源于此。
- 在 uniCloud 控制台 → 数据库 → 索引管理中,为每个含租户隔离的集合添加复合索引,例如:
["tenant_id", "created_at"]或["tenant_id", "status", "updated_at"] - 避免单字段索引
tenant_id—— 它对范围查询无效,实际作用极小 - 使用
db.collection().orderBy().limit()时,若排序字段不在 tenant_id 复合索引中,索引将失效
云存储文件路径必须携带 tenant_id 前缀
uniCloud 云存储 bucket 是全局共享的,uploadFile 若不强制路径隔离,A 租户上传的文件会被 B 租户通过构造 URL 直接访问。
- 上传时路径必须形如:
tenant_abc123/avatar/xxx.png,不能是avatar/xxx.png - 下载链接生成必须走
getTempFileURL,禁止拼接公开可猜路径;且该函数不校验租户,所以路径本身必须不可预测 - 删除文件前,先用
db.collection('files').where({ path: xxx }).get()校验该路径是否属于当前租户,再执行deleteFile
最容易被忽略的是云函数间调用 —— 比如 A 函数调用 B 函数处理审批流,B 函数若没重新校验租户上下文,就可能把 A 租户的数据误写入 C 租户的集合。这种链路污染很难排查,必须每一跳都做完整上下文透传与校验。


















