Firestore 安全规则:更新时 request.resource.data.<prop> 会发生啥?
Posted
技术标签:
【中文标题】Firestore 安全规则:更新时 request.resource.data.<prop> 会发生啥?【英文标题】:Firestore security rules: what happens with request.resource.data.<prop> on update?Firestore 安全规则:更新时 request.resource.data.<prop> 会发生什么? 【发布时间】:2018-08-06 07:32:03 【问题描述】:我的团队最近讨论过这个问题,但似乎无法确定实际/预期的行为:
如果您有如下安全规则:
match /categories/document=**
allow update: if request.auth.uid != null
&& request.resource.data.firstName is string
&& request.resource.data.lastName is string;
然后您使用以下数据创建从前端到 /categories/ 的更新语句:
firstName: 'A valid firstName'
那么安全规则应该通过还是失败?
在reference documentation,它说
开发人员提供的数据显示在 request.resource.data 中,其中 是包含字段和值的映射。未提供的字段 资源中存在的请求被添加到 request.resource.data
相关问题:
-
这是否意味着成功/失败取决于
节点?
如果有人尝试使用未更新的数据进行更新,会发生什么情况?
在安全规则中指定,即
age: 28
什么是
验证更新数据的推荐方法?
更详细的问题 3(模式问题) 假设你有这样的模型:
interface Category
firstName: string;
lastName: string;
age?: int;
groupId?: string;
现在我们创建一个像这样的安全规则:
match /categories/document=**
allow update: if request.auth.uid != null
&& request.resource.data.firstName is string
&& request.resource.data.lastName is string;
&& request.resource.data.age is int;
&& request.resource.data.groupId is string;
据我所知,我们有以下场景:
没有一个场景适合可选属性。因为如果您必须提供所有属性(如场景 1 中),它并不是真正的可选属性。如果你不提供它们,就像在场景 2 中一样,它会失败。
也许我在这里遗漏了一些东西,关于如何使用写入 firestore 的可选属性来验证数据的基本指南?
可选参数的安全规则,如下所示:
match /categories/document=**
allow update: if request.auth.uid != null
&& request.resource.data.firstName is string
&& request.resource.data.lastName is string;
&& request.resource.data.age is int; // ignore if NOT provided
&& request.resource.data.groupId is string; // ignore if NOT provided
【问题讨论】:
【参考方案1】:那么安全规则应该通过还是失败?
如果正在更新的文档已经有一个lastName
字段并且该字段是一个string
,那么更新将会成功。 (我假设您在经过身份验证时运行此更新,以便 request.auth.uid != null
返回 true)
回答相关问题:
-
是的,有时它可能取决于节点上的现有数据。
如果该文档已经设置了
firstName
和lastName
,则添加age
字段将成功。请注意,该规则仅检查这两个值是否为字符串。它没有指定文档不能超过 2 个字段。
这个问题听起来有点宽泛(我会说有点像XY problem)。请说明您正在尝试执行哪种更新验证。根据您的问题,我已经知道您正在尝试什么,但我想 100% 确定。
更新:
我从您更新的问题 3 中了解到,如果用户同时提供了名字和姓氏,您只想更新文档。年龄和 groupId 是可选的。
为此,您可以使用resource.data.firstName != request.resource.data.firstName
检查此request.resource.data.firstName
是否不在数据库中。所以你的安全规则应该是这样的:
match /categories/document=**
allow update: if request.auth.uid != null
&& (request.resource.data.firstName is string && resource.data.firstName != request.resource.data.firstName)
&& (request.resource.data.lastName is string && resource.data.firstName != request.resource.data.firstName)
&& request.resource.data.age is int
&& request.resource.data.groupId is string
现在使用这些规则,使用此数据的更新将失败:
firstName: 'A valid firstName'
虽然这三个都会成功:
firstName: 'A valid firstName',
lastName: 'A valid lastName'
firstName: 'A valid firstName',
lastName: 'A valid lastName',
age: 20
firstName: 'A valid firstName',
lastName: 'A valid lastName',
age: 20,
groupId: 'groupId'
更新 2: 要将 age
和 groupId
作为可选字段,请使用 OR 运算符和 hasAll()
函数检查请求是否包含这些字段:
match /categories/document=**
allow update: if request.auth.uid != null
&& (request.resource.data.firstName is string && resource.data.firstName != request.resource.data.firstName)
&& (request.resource.data.lastName is string && resource.data.firstName != request.resource.data.firstName)
|| (request.resource.data.keys().hasAll(['age']) && request.resource.data.age is int)
|| (request.resource.data.keys().hasAll(['groupId']) && request.resource.data.groupId is string)
【讨论】:
嗨罗萨里奥 - 感谢您的回答。我不认为这是一个 XY 问题,因为毕竟安全规则的目的不是帮助验证数据吗?我在问题中添加了更多细节:) 感谢您的更新!我也更新了答案 我查看了您的回答,得出的结论是您的回答只是部分正确。你说:“虽然这三个会成功”。但我认为情况并非如此。在第一种情况下,使用 firstName 和 lastName 创建会失败,因为安全规则会测试 request.resource.data.age 和 request.resource.groupId。 安全规则测试 age 是否为 int 且 groupId 是否为 string。不要忘记resource中存在的request中未提供的Fields被添加到request.resource.data中......如果这个age已经存在于数据库中并且是一个int,那么规则就会成功。 感谢您的解释。一开始我误会了。我已经用正确的方法更新了我的答案以上是关于Firestore 安全规则:更新时 request.resource.data.<prop> 会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法使用Firestore安全规则使用FieldValue.increment()更新文档字段?