跳到主要内容
Data 与 Schema

本页尚未翻译,当前显示英文版本。

访问控制

最后更新:2026 年 8 月 26 日

访问控制决定的是谁有资格碰每一张 Table。它回答的问题和认证不同:登录确立的是_调用方是谁_,访问控制确立的是_这个调用方可以做什么_。这套模型有意做得简单 —— 按 Table 划分 Read 和 Write,按 Function 划分 Execute,面向三类调用方 —— 再配合按 Player 划分的行归属。

信息

默认情况下,游戏 client 能读不能写,而一张新建的 Table 对 client 是完全关闭的。你要按调用方、按 Table 有意识地逐一放开。如果 client 的调用因权限不足被拒,说了算的是运行时 —— 客户端一侧的检查可以提前拒绝,但它从不授予权限。


三种 subject

每一次运行时调用都会解析出唯一一个 subject,依据是它本就携带的凭据。

Subject是谁
client你的游戏客户端 —— 公开的 pk_... key,无论有没有已登录的 Player
server你自己的服务器 —— 保密的 sk_... key(game server、脚本、CI)
backend你的服务端 Functions —— 云函数那一层

Backoffice(操作者)那一层是独立的,从不受这些 Table 设置的限制。


两层叠加

访问权限按固定顺序判定:先看权限,再看行作用域。

  1. Table 权限 —— 这个 subject 究竟能不能读或写这张 Table?不能,则调用以 403 被拒,后面的一概不看。
  2. 行作用域 —— 对于处在 owned by a player 的 Table 上的 client,哪些行可见?Player 看得到自己的行;别人的行不可见。
调用 + 凭据→ subject权限Read / Write 开关否 → 403 forbidden行作用域owned Table 上的 client仅限自己的行他人的行404 —— 不可见

Table 权限

每张 Table 都为每个 subject 各带一个 Read 开关和一个 Write 开关。Write 涵盖所有修改 —— 创建、更新和删除一视同仁,没有单独的删除权限。

SubjectRead 默认Write 默认
clientoffoff
serveronon
backendonon

新建的 Table 在两个方向上都是对 client 关闭的,而对 server 和 backend 开放。这就是为什么 client 对一张新 Table 调用 Update() 会被拒,直到你放开 client.write —— 这道写入边界是安全默认值,不是 bug。

警告

在一张并非 owned by a player 的 Table 上放开 client.write,等于让任何 client 都能写它的任何一行 —— 也就是共享状态、世界状态那种场景。只有 owned by a player 的 Table 才会把 client 的写入限制在调用方自己身上(见下)。放开无限制的 client 写入,请出于明确的判断。


client 的行归属

在标记为 owned by player 的 Table 上,Table 权限依然决定 client 能不能 碰它;行归属接着决定 能碰哪些行。

  • Read owner —— client 只看得到自己的行。
  • Read public —— client 看得到所有行(归属不限制读取)。
  • Write —— client 创建时,会把当前行动的那个 Player 盖章为归属者;更新和删除只在调用方自己的行上才成功。
  • server 和 backend 从不受限 —— 它们读写任意行。

归属于其他 Player 的行被当作不可见,而不是“禁止访问”:读取、更新或删除它都返回 404 —— 与一行根本不存在时完全相同的结果。这是有意为之,好让写入路径永远不会泄露读取路径藏起来的行。

备注

既然他人的行和不存在的行在设计上就无从区分,就不要在 client 代码里依赖这个差别 —— 两者都只会返回一个普通的 not-found。


Function 的 Execute

每个 Function 都为各个 subject —— client、server、backend —— 各带一个 Execute 开关,默认全部开启。没有 Execute 的 subject 会以 403 被拒。

Execute 与 Function 的 Auth 要求(none 或 player)是两回事:Auth 管的是_匿名 client 能不能调用_,Execute 管的是_这个 subject 是否被允许_。没有已登录 Player 的 client 去调用一个 player auth 的 Function,无论 Execute 如何都会以 401 被拒。


调用被拒时

情形结果
subject 在该 Table 上没有 Read403 table_read_forbidden
subject 在该 Table 上没有 Write403 table_write_forbidden
subject 在该 Function 上没有 Execute403 function_execute_forbidden
匿名 client 读取按 owner 划分作用域的 Table403 owner_read_requires_player
匿名 client 写入 owned 的 Table422 acting_player_required
client 在没有 Player 的情况下调用 player auth 的 Function401 player_auth_required
client 碰了归属于其他 Player 的行404 not_found(不可见)
client 读取其他 Player 的账号403 player_read_forbidden

提示

如果 client 的写入意外被拒,先看这张 Table 的 client.write 开关,再看它是不是 owned by a player、以及你是否正以那一行归属者的身份行动。这两点合起来,几乎能解释数据面上的每一个 403 / 404。


下一步

更新于 2026年8月26日