【问题标题】:Firestore security rules - permission deniedFirestore 安全规则 - 权限被拒绝
【发布时间】:2020-03-22 03:33:13
【问题描述】:

我有一个用户集合,用于存储用户数据,例如姓名、电子邮件等,以及另一个用于被阻止用户的集合。我想让用户阅读自己的文档和他/她没有阻止的用户的文档。我已经实施了安全规则,但不知何故,用户甚至无法阅读自己的文档。有人可以帮忙吗?

用户收藏

users { // name of collection
   a1 { // this is firebase id serving as document name
     name: "abc",
     email: abc@gmail.com
   }
   a2 { // this is firebase id serving as document name
     name: "efg",
     email: efg@gmail.com
   }
   a3 { // this is firebase id serving as document name
     name: "hij",
     email: hij@gmail.com
   }
   a4 { // this is firebase id serving as document name
     name: "klm",
     email: klm@gmail.com
   }
}

阻止收集

blocked { // name of the collection
    a1 { // name of the document
        a2 : 1, // this means a1 has blocked a2
        a4 : 1  // this means a1 has blocked a4
    }
}

安全规则

service cloud.firestore {
    match /databases/{database}/documents {
        match /users/{userId} {
            allow read: if request.auth.uid != null
            && get(/databases/$(database)/documents/blocked/$(request.auth.uid)).userId != 1;
        }

        match /blocked/{fid} { // blocked collection/fid == owner firebase id
            allow read: if request.auth.uid == fid;
        }
    }
}

代码

DocumentReference docref = Firestore.instance.collection("users").document(user.uid);
return docref.get();

【问题讨论】:

  • 请使用在这些规则到位后无法按照您期望的方式工作的代码编辑问题。规则必须始终有一些匹配的代码与它们一起使用才能有意义。查看用于特定查询的文档的确切内容也将很有帮助。换句话说,请提供一个 mcve。 stackoverflow.com/help/minimal-reproducible-example
  • 感谢@DougStevenson,我什至无法获得自己的文档参考。请看上面的代码
  • 您在规则中错误地使用了get()。它返回一个 Resource 对象,该对象具有所有字段值所在的数据属性。请注意,访问不存在的属性是错误的,并且会导致规则始终拒绝。我还建议使用布尔值而不是数字来指示被阻止的用户。 firebase.google.com/docs/reference/rules/rules.firestore#.get
  • @RobinChander 更一般地说,想想你想如何测试规则——包括允许和拒绝情况,以及你将进行什么查询——你提到的单个 get() 可以用也只是开放阅读规则。我确实相信我的回答应该让你得到你在这篇文章中描述的内容(主要问题是 Doug 描述的内容),但它实际上可能不是你所需要的。
  • 谢谢大家。我意识到我确实使用不正确。我也试图错误地使用规则来过滤。

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


【解决方案1】:

在这种情况下,您需要以不同的方式处理 userId 变量。按照您编写的方式,规则是在用户的被阻止文档的Resource 对象中查找userId 属性,而不是userId 变量的值。您可能还想为get 调用提供一个合理的默认值。

同样,由于get() 调用返回Resource,您需要使用data 成员来获取Map 属性。

您可能还需要检查用户的被阻止文档是否确实存在,否则如果不存在,您的查询将失败。

service cloud.firestore {
    match /databases/{database}/documents {
        match /users/{userId} {
            allow read: if request.auth.uid != null
                && (!exists(/databases/$(database)/documents/blocked/$(request.auth.uid)) ||
                    get(/databases/$(database)/documents/blocked/$(request.auth.uid)).data.get(userId,0) != 1);
        }

        match /blocked/{fid} { // blocked collection/fid == owner firebase id
            allow read: if request.auth.uid == fid;
        }
    }
}

以上内容应该允许(鉴于您在问题中定义的/blocked):

  • 用户a1阅读/users/a1
  • 用户a1阅读/users/a3
  • 用户a2阅读/users中的任何文档

以上应该否认:

  • 所有写入
  • 用户a1阅读/users/a2

我只在模拟器中对上述内容进行了一些松散的验证。对于您最终使用的任何规则,我强烈建议您 write extensive tests

最后,请记住security rules are not filters,所以这实际上取决于您如何使用它——any 可能匹配文档可能被拒绝的查询将拒绝整个查询。您描述问题的方式(使用规则让用户被拒绝访问他们已阻止的其他用户的文档)听起来像是在尝试过滤,而不是尝试保护数据。

【讨论】:

  • 谢谢@robsimb。这很有帮助。是的,我试图使用规则过滤数据。因为不等式检查在 Firestore 中不可用,而且我真的不想进行不必要的读取。
  • 是的,安全规则对你不起作用。碰巧的是,get() 调用无论如何都会对您进行读取收费,因此它显然不会保存读取。
  • 我同意。有道理。
猜你喜欢
  • 2016-11-27
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
  • 1970-01-01
  • 1970-01-01
  • 2020-08-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多