2.4 集合权限:谁能读谁能写

表建好那晚我本该收工,但临睡前手贱把 posts 集合的权限点成了 所有用户可读写,想着先方便调试。第二天合伙人测试时随手发了一条记录,然后问我:咱的文章列表里怎么多了一条别人的测试数据?细查才发现 anyone 都能往集合里写。文档型数据库没有账户密码这一层防线,权限模型就是唯一的大门,这一节专门讲这扇门怎么装。

场景:没有密码的数据库怎么防身

传统数据库靠账号密码和网络隔离,云开发的数据库是直接暴露在 SDK 面前的:前端拿到初始化配置后,就能直接读写数据库。安全完全依赖集合的权限规则。换句话说,权限配错等于把数据库开着门放在大马路上。

这个模型理解上有两个常见误区。其一是以为云函数和前端走同一套权限:实际云函数默认以管理员身份运行,规则拦不住它,所以 写操作收进云函数 这句话既是开发规范也是安全设计。其二是以为权限和代码里的是同一道防线:权限是数据库层的最后一道闸门,代码里漏掉鉴权,数据库规则还能兜底;规则一旦放开,就再没有任何屏障。想清楚这两层关系,后面的配置才不会配得不明不白。

我们的权限目标分四档:

  • 文章列表、详情:所有人可读
  • 发布文章:必须登录
  • 点赞计数:登录用户可改自己的记录
  • 用户表 openid 等敏感字段:只允许本人读

这四档后来一一对应到下面方案表里的几种内置模式。目标先列清楚,配置才有方向,不然面对控制台的下拉框很容易随手选默认值,而默认值往往是最宽松的那一档。

四档目标的落地还有一个隐藏好处:新人接手项目时,权限目标比权限配置本身更好读懂。我们把这四行贴在项目文档首页,谁都能一眼看懂数据的边界在哪。另外要注意权限模式是集合级的,一个集合只有一套模式,没法按字段细粒度控制。字段级控制必须靠自定义规则或挪字段:敏感字段拆进单独集合并收紧权限,是常用的迂回方案。

方案:四种权限模型选哪个

云开发给每个集合提供了四种内置权限,对照表如下:

权限模式 读 写 适用场景
仅创建者可读写 自己 自己 私密数据,如个人草稿
所有用户可读,仅创建者可写 所有人 自己 论坛帖子、公开文章
仅创建者可读写(含管理员) 自己和管理员 自己和管理员 敏感数据兜底
所有用户可读写 所有人 所有人 几乎没有适用场景

posts 用的是第二种:所有用户可读、仅创建者可写。配合 status 字段实现草稿/发布控制,写入限制在创建者身份上。这个模式命中了图文应用九成的集合,远比自定义规则省心。

users 集合敏感一些,默认走第一种加白名单:本人可读写,管理员可读。openid 字段如果不锁住,理论上可以被遍历,虽然利用门槛高,但配上零成本,数据表设计完成后第一时间就改掉了默认权限。

控制台操作路径:数据库面板选中集合,点权限设置,切换模式保存即可,秒级生效。也可以用 CLI 批量查一组集合的权限状态,巡检时一行命令覆盖全部:

# 批量看权限
tcb db list-collections -e my-app-prod
# 设为 所有用户可读,仅创建者可写(对应模式标识)
tcb db update-permission posts --mode readonly

需要更细的控制就走自定义安全规则(JSON 语法),比如只允许审核通过的文章被读:

// posts 自定义规则示例
{
  "read": "doc.status == 1 || auth.openid == doc._openid",
  "write": "auth.openid == doc._openid"
}

这行的意思是:已发布的文章任何人可读,否则只有作者本人可读;写操作一律只有作者。规则语法细节可以翻本书目录对应的权限章节,也可以在腾讯云实践里找到同类配置的线上案例。

自定义规则里有几个常用表达式值得记住,日常配置基本都由它们组合而成:

表达式 含义 我们用在哪
auth.openid 当前登录用户身份 判断是否作者
doc._openid 文档作者 与 auth 对比
auth.uid 用户 UID users 集合规则
doc.status 业务字段 内容审核联动
&& 和

组合的能力上限其实很高:点赞集合可以用 是否本人 点过 做防重复写;评论集合可以写成 任何人可读、登录可写。只要规则能描述清楚,就不用在云函数里手写鉴权代码,省下的逻辑全是真金白银的开发时间。

上线前我们用了一招很好用的验证办法:把规则在测试环境铺好后,用三个不同身份(未登录、作者本人、其他登录用户)分别走一遍读和写,把结果填进一张预期对照表。凡是实际结果与预期不符的格子,都是规则写错的地方。这张表后来随权限一起进了项目文档,每次改规则回归一遍,比事后看日志高效得多。

踩坑:门没锁好的几种姿势

姿势一:调试时临时打开全部权限忘记关。 就是开篇自食的那颗果实。补救:上线 checklist 里强制一条 逐个集合核对权限,并写成一个脚本放在部署流程里跑。

姿势二:过度信任前端校验。 发布文章时前端拦了未登录用户,但数据库权限是 所有人可写,懂行的人绕过前端直接写库。教训:前端只做体验,权限才是底线,凡是写操作至少要用 仅创建者可写挡一层。

姿势三:权限挡住了正常业务。 用了 仅创建者可读写之后,编辑文章时前端报无权限。查了才发现编辑功能是云函数代写的,绕过了用户身份。云函数侧有管理员权限不受限,这条链路是通的,但当时多云函数混用,其中一个用了 SDK 用户态调用,身份对不上。解决方案是所有写操作统一收进 CloudBase 管理员态的云函数,前端永远只调函数不直接写库。云函数里怎么拿到完整身份上下文,见云函数创建一节。

姿势四:规则改了不回滚旧库。 posts 历史数据里早先的文档没有 _openid 字段(脚本导入的),切到 仅创建者可写后这批文档作者本人也改不了。写个脚本补上 _openid 再切权限,顺序不能反。

姿势五:子集合权限独立。 评论集合和文章集合权限模式不同,但一批改权限时只改了 posts,评论留下的开放写权限又被钻了空子。批量巡检脚本要覆盖全部集合,别只盯核心集合。走到内容审核一节会发现,审核状态字段的读写同样要权限兜底,违规内容隔离全靠它。

上线前的权限检查清单

我们团队每次部署前过一遍这个清单,后来基本没再出过权限事故:

检查项 期望状态 频次
posts 权限模式 所有用户可读,仅创建者可写 每次部署
users 权限模式 仅创建者可读写加管理员 每次部署
敏感集合清单 无 所有人可写 项 每周巡检
前端直接写库的调用 为零,全部走云函数 每次发版
自定义规则语法 控制台规则校验通过 修改即查

清单里的前两条对照本节上文的模式表,后三条是血泪换来的补充。第一次跑清单肯定能查出几处,跑顺了之后就是五分钟的事。

小结

数据库没有密码,权限就是全部防线。四档内置权限里记牢一句话:读可以大方,写必须收敛。所有集合默认从 仅创建者可写起步,需要放开的再单独放开,这个方向永远比出事后收紧安全。配合云函数管理员态做写操作、前端只读加调函数,这套组合拳既安全又不牺牲开发效率。

这一节讲完,环境、数据库表、权限三件事就齐了,第二章收尾。下一篇我们进入云函数:核心逻辑放云端,把列表、发布、点赞这些业务逻辑真正写起来。权限和云函数是套装关系,权限管数据的大门,云函数管业务的逻辑,两者怎么配合贯穿后面整本书,遇到写操作权限冲突时随时回来翻这节。

最后给一个实用的自查思路:任何一次线上数据事故,按 数据怎么进来的 倒推排查,第一站永远是权限模式。我们出过一次点赞数异常增长,查到last不是代码 bug,而是 likes 集合权限被一次批量操作带成了 所有人可写。倒推法加上前文的清单表,是这套权限体系最小的运维工具箱,配合监控与成本一节的日志检索,定位这类问题一般不超过半小时。

延伸阅读