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)

回答相关问题:

    是的,有时它可能取决于节点上的现有数据。 如果该文档已经设置了firstNamelastName,则添加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: 要将 agegroupId 作为可选字段,请使用 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 安全规则:更新已禁用,但更新完美

有没有办法使用Firestore安全规则使用FieldValue.increment()更新文档字段?

Firebase Firestore更新时间字段安全问题

Firestore:删除文档和安全规则

即使firestore安全规则中的文档字段不可用,也如何允许访问?

在 Firestore 安全规则“列表”操作中使用变量