【问题标题】: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

相关问题:

  1. 这是否意味着成功/失败取决于 节点?
  2. 如果有人尝试使用未更新的数据进行更新,会发生什么情况? 在安全规则中指定,即{age: 28}
  3. 什么是 验证更新数据的推荐方法?

更详细的问题 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
}

【问题讨论】:

    标签: firebase google-cloud-firestore firebase-security


    【解决方案1】:

    那么安全规则应该通过还是失败?

    如果正在更新的文档已经有一个lastName 字段并且该字段是一个string,那么更新将会成功。 (我假设您在经过身份验证时运行此更新,以便 request.auth.uid != null 返回 true)

    回答相关问题:

    1. 是的,有时它可能取决于节点上的现有数据。
    2. 如果该文档已经设置了firstNamelastName,则添加age 字段将成功。请注意,该规则仅检查这两个值是否为字符串。它没有指定文档不能超过 2 个字段。
    3. 这个问题听起来有点宽泛(我会说有点像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,那么规则就会成功。
    • 感谢您的解释。一开始我误会了。我已经用正确的方法更新了我的答案
    猜你喜欢
    • 1970-01-01
    • 2020-06-19
    • 2019-01-09
    • 2019-01-15
    • 2018-03-27
    • 2018-10-19
    • 2019-07-05
    • 2019-06-17
    相关资源
    最近更新 更多