流水线操作的安全规则
借助流水线操作规则,您可以匹配现有规则引擎的过滤功能。虽然流水线操作提供了一组丰富的功能,但规则引擎仅限于识别简单过滤条件,以确保查询的可满足性和安全性。
版本和模式要求
本文档适用于原生模式下的 Firestore 企业版。
支持的过滤表达式
如需通过规则限制查询,查询必须使用标准比较运算符与常量进行比较。规则引擎可识别以下过滤条件类型:
- 等式和不等式:
eq、neq。 - 比较:
gt、gte、lt、lte。 - 成员:
in、arrayContains
下面是一些示例:
where(eq("foo", 2))where(lt("foo", 2))documents("/user/1", "/user/2").where(...)
请求属性
您可以继续使用 request 对象来验证身份验证和查询上下文,不过流水线不支持标准查询中的某些属性。
支持的属性
新版引擎继续支持以下属性:
request.auth:访问用户 UID 和 token 数据。request.method:标识操作(例如get、list)。request.path:所访问资源的路径。request.time:请求的服务器端时间戳。
不支持的属性
由于在多阶段查询中确定这些值的复杂性,流水线规则检查不支持 request.query 属性(例如 limit、offset 和 orderBy)。
流水线阶段处理和权限
不同的流水线阶段会映射到安全规则中的特定粒度操作:
allow list权限:由collection()、collectionGroup()和database()阶段触发。allow get权限:由documents()阶段触发,该阶段的处理方式与批量get操作类似。allow create权限:由insert()阶段以及创建新文档时的upsert()阶段触发。allow update权限:由update()阶段触发,以及在更新现有文档时由upsert()阶段触发。allow delete权限:由delete()阶段触发。allow write权限:适用于所有 DML 操作(insert()、update()、upsert()和delete())。- 字段修改阶段:规则仅对存储的数据进行操作,而不对派生值进行操作。如果流水线包含修改字段(例如
AddFields、ReplaceWith、Select)的阶段,则规则引擎在遇到该阶段后会停止应用过滤条件限制。 - 字面量阶段:
literals()阶段不从数据库读取数据,但可能会产生费用。为防止滥用,它必须与另一个可通过规则验证的阶段(例如collection())配对。
数据操纵语言 (DML) 阶段和安全规则
执行数据操纵语言 (DML) 阶段(insert()、update()、upsert() 和 delete())时,安全规则评估权限的方式与读取查询不同:
- 逐文档规则评估:与读取流水线不同,DML 操作会针对每个单独的文档变更评估安全规则,而读取流水线需要预先使用过滤表达式在规划时限制查询。
- 规则变量:
request.resource:包含insert()、update()和upsert()操作的建议文档数据。resource:包含修改前存储在数据库中的当前文档数据(适用于现有文档的update()、delete()和upsert())。
DML 的系统限制和执行行为
使用安全规则运行 DML 操作时,请注意以下系统限制和执行行为:
get() 和 exists() 的 20 次查找限制
Firebase 安全规则允许在整个请求中最多执行 20 次文档查找(get() 或 exists())。
当 DML 流水线在显式事务之外运行时,文档会分批处理。由于每个批次都在自己的事务中执行,并且文档可能会在批次之间并发修改,因此系统会针对每个写入批次重新评估安全规则和文档查找。
即使您的安全规则是针对单个静态文档进行评估,例如检查用户是否为管理员:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin == true;
}
}
}
每个文档写入批次都会执行一次查找。因此,在写入所有可能的文档后,请求达到 20 次查找限制,流水线失败并显示 PERMISSION_DENIED 错误。此外,每个写入批次执行的每次查找都会产生各自的读取费用。
部分成功和 PERMISSION_DENIED
在事务外部执行时,DML 操作会按顺序批量提交写入。如果某个批次失败(原因可能是文档不符合规则条件,也可能是超出了 20 次查找的限制),流水线会停止并返回 PERMISSION_DENIED 错误。
不过,已提交的批次不会回滚。数据库仍处于部分更新状态。由于客户端收到的错误不包含已修改文档的列表,因此您必须查询数据以检查哪些写入操作成功。
使用 Cloud Audit Logs 诊断规则失败问题
出于安全原因,面向客户端的 PERMISSION_DENIED 错误不会披露哪个安全规则条件失败或是否达到了 20 次查找限制。
如需诊断规则评估失败问题,项目管理员可以在 Google Cloud 控制台中(在 Firestore > 监控下或在 Logs Explorer 中)检查 Cloud Audit Logs,以查看详细的 EvaluationError 条目。