【问题标题】:Firebase Firestore subcollection secure queryFirebase Firestore 子集合安全查询
【发布时间】:2018-03-22 22:00:56
【问题描述】:

我的 Cloud Firestore 数据库中有以下规则:

service cloud.firestore {
  match /databases/{database}/documents {
    match /performances/{performanceId} {
      allow read, update, delete: if request.auth.uid == resource.data.owner;
      allow create: if request.auth.uid != null;
    }
  }
}

这个想法是,如果您拥有表演,则可以读取和写入表演,或者如果您已登录,则可以创建表演。

这个查询工作正常:

db.collection("performances").whereEqualTo(FieldPath.of("owner"), user.getUid())

但是,如果我想获取“场景”子集合的内容,则会收到错误消息:“com.google.firebase.firestore.FirebaseFirestoreException:PERMISSION_DENIED:权限缺失或不足。” 这与以下查询有关:

db.collection("performances")
            .document(performanceID)
            .collection("scenes");

我假设我需要将查询限制为以下内容,但这不会起作用,因为 whereEqualTo 的输出是查询而不是 CollectionReference,因此我无法访问“文档”:

db.collection("performances")
   .whereEqualTo(FieldPath.of("owner"), user.getUid())
   .document(performanceID)
   .collection("scenes");

那么,如果主集合有安全规则,有谁知道我应该如何访问子集合?

更新1(因为下面评论中的代码没有格式化)

我想我可能想出了一个解决方案。我没有意识到默认情况下我的安全规则会拒绝从子集合中读取,因此将其更改为允许对表演中的场景进行所有读取和写入使其正常工作:

service cloud.firestore {
  match /databases/{database}/documents {
    match /performances/{performanceId} {
      allow read, update, delete: if request.auth.uid == resource.data.owner;
      allow create: if request.auth.uid != null;
      
      match /scenes/{sceneId} {
        allow read, write: if true
      }
    }
  }
}

【问题讨论】:

  • 我想我可能想出了一个解决方案。我没有意识到默认情况下我的安全规则会拒绝从子集合中读取,因此将其更改为允许对性能中的场景进行所有读取和写入使其工作正常: service cloud.firestore { match /databases/{database}/documents { match /performances/{performanceId} { 允许读取、更新、删除:如果 request.auth.uid == resource.data.owner;允许创建:如果 request.auth.uid != null;匹配 /scenes/{sceneId} { 允许读取,写入:如果为真 } } } }
  • 还可以查看通配符语法{name=**}firebase.google.com/docs/firestore/security/…

标签: android firebase google-cloud-firestore


【解决方案1】:

首先,请注意规则不会级联,因此您的解决方案实际上向全世界开放了所有 scenes 子集合中的所有文档,而不仅仅是父文档的所有者。

您需要使用规则中的get() 方法检查父文档的权限。

service cloud.firestore {
   match /databases/{database}/documents {
      match /performances/{performanceId} {
         allow read, update, delete: if request.auth.uid == resource.data.owner;
         allow create: if request.auth.uid != null;

         function parentDoc() {
             return get(/databases/$(database)/documents/performances/$(performanceId)).data;
         }

         match /scenes/{sceneId} {
            allow read, write: if parentDoc().owner = request.auth.uid;
         }
      }
   }
}

这里在子集合规则中我们使用之前捕获的路径段来查找我们需要检查的父文档。

最后,您可能还想收紧create 规则。目前它允许某人创建由其他人(或没有人)拥有的文档。我怀疑你想要那个。通过检查请求者的 id 是否在传入文档中,您可以防止潜在的错误,这些错误允许创建用户随后无法阅读的文档:

allow create: if request.auth.uid != null && request.auth.uid == request.resource.data.owner;

【讨论】:

  • 这真的很有帮助,谢谢,我没有意识到父文档中的规则也不会影响嵌套集合。
  • parentDoc() 函数对我检查所有权非常有帮助。谢谢!
猜你喜欢
  • 2020-10-10
  • 2020-11-21
  • 2019-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-19
相关资源
最近更新 更多