【问题标题】:Why does a Firestore security rule using get() not work while another rule using resource.data works?为什么使用 get() 的 Firestore 安全规则不起作用,而使用 resource.data 的另一个规则起作用?
【发布时间】:2021-01-06 17:44:56
【问题描述】:

为了适应 Cloud Firestore,我一直在开发聊天应用程序。
下面是它的数据库结构。

rooms
  ├ xxxxxx
  │  ├ messages
  │  │  ├ xxxxxx
  │  │  └ xxxxxx
  │  └ private
  │      └ allowed - members [xxxxxxxx, xxxxxxxx]
  └ xxxxxx
      ├ messages
      │  ├ xxxxxx
      │  └ xxxxxx
      └ private
          └ allowed - members [xxxxxxxx, xxxxxxxx]

每个聊天室文档下的private子集合都有一个文档,其ID为allowed
allowedmembers,这是一个数组字段,包含允许使用聊天的用户的ID房间。

要获取特定聊天室,我首先要做的是获取allowed 文档,如下所示:

db.collectionGroup('private')
  .where('members', 'array-contains', userId)
  .get()
  .then(...)

我已经在private 上为集合组查询创建了一个索引,所以上面的代码有效。

但是,如果我添加以下安全规则,它会失败并显示错误消息“未捕获(承诺中)FirebaseError:缺少权限或权限不足。”

match /{path=**}/private/{document} {
  allow read: if request.auth.uid
    in get(/databases/$(database)/documents/$(path)/private/$(document)).data.members;
}

此规则用于禁止非房间成员的用户访问allowed
没有.where(...) 的查询会导致同样的错误。

另一方面,以下规则按预期工作。

match /{path=**}/private/{document} {
  allow read: if request.auth.uid in resource.data.members;
}

我知道这条规则要好得多,所以我肯定会使用它,但我仍然想知道为什么以前的规则不起作用。
有人能解释一下原因吗?



这有什么关系吗?

【问题讨论】:

    标签: google-cloud-firestore firebase-security


    【解决方案1】:

    您的安全规则是为 collectionGroup /{path=**}/private 编写的,一方面 - 所写的这条规则适用于任何名为“private”的集合,无论它在哪里。另外,您尝试使用变量$(rule),我没有看到它的定义。

    安全规则仅适用于匹配查询 - 您必须确保您的查询explicity 不会导致不允许的文档。 如果查询可能产生一个不允许的文档(即由安全规则指定),那么整个查询将被拒绝 - 不仅仅是不允许的文档.安全规则是全有或全无 - 这就是它们可扩展的原因。

    【讨论】:

    • 糟糕,这是我的错。我错误地粘贴了我之前尝试过的规则之一,对不起!实际的get() 部分是get(/databases/$(database)/documents/$(path)/private/$(document)).data.members;,这也不起作用。
    • 至于规则只适用于匹配查询的事实,我已经注意到了,因此粘贴了相关描述的屏幕截图。我的问题是,为什么它会影响我的查询?我猜where('members', 'array-contains', userId) 是仅获取允许文档的条件。错了吗?
    • 是的,我知道。安全规则可以在 .get() 中获取 一个 文档。但是您的查询(上面)可以匹配 many 个文档,因为 ${path=**} 是后跟 /private 的任何路径,而 collectionGroup 查询中的 {document} 表示一组 个文档,而不仅仅是一个。我遇到了这种种类的问题(我使用了很多collectionGroups),它们可能相当很难让安全规则正确。
    • 谢谢!听起来很合理。据我了解,.get(many documents).data.members 是以不正确的方式从数组中的多个对象中获取每个members 字段的操作;几乎就像[{members: ['a', 'b']}, {members: ['a', 'b']}].members,在各种编程语言中都是错误的。
    • 您能否编辑您的答案,以便我将其选为最佳答案?
    猜你喜欢
    • 2018-03-19
    • 2021-05-12
    • 2019-01-31
    • 2021-11-22
    • 2019-09-06
    • 2018-05-28
    • 2020-08-24
    • 1970-01-01
    相关资源
    最近更新 更多