【问题标题】:Firestore security rule: query subcollection based on permission of parent documentFirestore安全规则:根据父文档权限查询子集合
【发布时间】:2021-07-17 02:13:09
【问题描述】:

假设我有一个restaurants 集合和menus 子集合。餐厅权限设置在餐厅文档中,如下所示:

餐厅

{
 "roles": {
    "user123": "Owner"
  }
}

有权访问该餐厅的任何人也可以访问其任何子集合,包括 menus 子集合。以下是安全规则:

安全规则

match /restaurants/{restaurantId}/{document=**} {
  allow read: if resource.data.roles[request.auth.uid] > '' ;
}

查询餐厅列表可以这样完成,效果很好:

餐厅查询

firebase
      .firestore()
      .collection('restaurants')
      .where(`roles.${uid}`, '>', '');

现在如何查询menus 子集合?我了解 Firestore 需要在不查看基础数据的情况下根据查询推断权限。从逻辑上讲,这应该是可能的,因为任何可以访问restaurant 的人也可以访问menus 子集合。但是我如何编写这个 menus 子集合查询以便 Firestore 可以推断出来呢?我能想到的最合乎逻辑的查询是这样的:

查询菜单子集合(不起作用)

firebase
     .firestore()
     .doc(`restaurants/${restaurantId}`) // user has access to this restaurant
     .collection('menus');

...但这不适用于权限被拒绝。

【问题讨论】:

  • =** 中的 match /restaurants/{restaurantId}/{document=**} 表示该规则适用于餐厅文档及其下的所有内容。但是这些菜单是否满足此要求:resource.data.roles[request.auth.uid] > ''
  • @FrankvanPuffelen 哦,这是一个很好的观点。菜单中没有roles,所以这可能是问题所在。我最初尝试过这个:get(/databases/$(database)/documents/restaurants/$(restaurantId)).data.roles[request.auth.uid] > '',但它看起来不像getexists 允许用于列表查询。你知道我该怎么做吗?
  • 如果需要,我不介意为 menus 子集合创建另一条规则,但即便如此,我也不确定如何让 Firestore 根据父 restaurant 中的 roles

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


【解决方案1】:

事实证明,我需要在restaurant 级别创建 2 个安全规则才能实现我想要的:

    match /restaurants/{restaurantId} {
      allow read: if resource.data.roles[request.auth.uid] > ''
    }

    match /restaurant/{restaurantId}/{document=**} {
      allow read: if get(/databases/$(database)/documents/restaurants/$(restaurantId)).data.roles[request.auth.uid] > '';
    }

为了查询用户有权访问的餐馆,第一条规则是必需的。单独的第二个查询不起作用,虽然我不知道为什么。这是第一条规则的查询:

firebase
      .firestore()
      .collection('restaurants')
      .where(`roles.${uid}`, '>', '');

第二条规则对于所有子集合查询都是必需的。这是一个例子:

firebase
      .firestore()
      .collection(`restaurants/${restaurantId}/menus`);

第二条规则允许子集合查询这一事实非常有趣,因为 Firestore 需要读取 restaurant 文档才能允许此查询。这与其声称它不查看基础数据以进行查询的说法相矛盾,但如果它只需要读取路径中的一个文档,它看起来确实如此。

【讨论】:

  • 很高兴听到您成功了! ? 我永远不确定规则引擎有多聪明。如:过去我对此感到惊讶。在这里我可以想象它实际上能够证明您在子集合上的条件对于您在父文档上的条件总是正确的。
  • @FrankvanPuffelen 是的,但我是否正确地得出这样的结论:Firestore 必须查看餐厅数据才能允许子集合查询?我觉得这很有趣,因为它确实解释了很多关于这些规则是如何工作的。
  • 不能查询条件规则。即:使用规则从集合中过滤文档。正如 Firebase 团队所说,对于您以后的规则,“规则是保镖,而不是防火墙”,这应该有效。因为角色对于该子集合是全局的。
  • @JohnnyOshika 我不确定它是否必须这样做,但您可以尝试只阅读子集合而不阅读父文档。即使是这样,这可能仍然符合指南,因为它不必检查 每个 文档来检查它是否符合标准,它只需要检查(单个)父文档.如果这确实是这里发生的情况,例如,您可以不使用相同的规则来允许集合 group 查询,因为这意味着规则引擎将不得不查看许多文档 - 包括那些还不存在。
  • @FrankvanPuffelen 实际上,如果您在上面的答案中查看我的子集合查询示例,我没有阅读父文档,因此 Firestore 必须阅读父文档以检查子集合的权限。关于这一点的好处仍然与 Firestore 一致,不必检查每个文档。至于集合组查询,这是一个有趣的问题。我想知道是否允许使用已经定义的规则,因为规则引擎需要检查许多父文档。
猜你喜欢
  • 2019-10-15
  • 1970-01-01
  • 1970-01-01
  • 2021-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-20
相关资源
最近更新 更多