Firebase规则表现得非常奇怪

Firebase规则表现得非常奇怪,firebase,flutter,dart,google-cloud-firestore,firebase-security,Firebase,Flutter,Dart,Google Cloud Firestore,Firebase Security,大家好,读到这篇文章的人 我正在为一家医院编写一个颤振应用程序,它具有这种db结构 我在获取会话数据时遇到问题,正是以下文档 使用以下方法获取治疗师进行的最后一次治疗,使用他的治疗师ID作为过滤字段 Future<Session> getLastSession() async { Query query; query = Firestore.instance .collection("sessions") .where("th

大家好,读到这篇文章的人

我正在为一家医院编写一个颤振应用程序,它具有这种db结构

我在获取会话数据时遇到问题,正是以下文档

使用以下方法获取治疗师进行的最后一次治疗,使用他的治疗师ID作为过滤字段

Future<Session> getLastSession() async {
 Query query;
 query = Firestore.instance
     .collection("sessions")
     .where("therapistUID",
         isEqualTo: this.uid)
     .orderBy("date", descending: true)
     .limit(1); //this.uid = auth uid of current therapist.
 try {

  QuerySnapshot querySnapshot = await query.getDocuments(); //exception thrown here

  if (querySnapshot.documents.isEmpty) {
    throw Exception("Empty query");
  } else {
    lastSession = Session.fromDocument(querySnapshot.documents[0]);
    return lastSession;
  }
} catch (e) {
  throw Exception("cannot get data from database");
}}
代码正在引发此异常


有人知道它为什么拒绝这个查询吗?请记住,查询只有一个文档,而且数据库中只有一个文档适合这些过滤器。使用具有相同参数的testlab可以工作。

无论您请求多少文档—Firestore安全规则。请阅读并理解本文档。它不允许您有条件地检查每个文档的某些内容,以确定它是否可以读取。您的规则试图表示,对于每次会话读取,匹配的患者文档中必须存在某些内容,但这是不允许的。它无法按Firestore所需的方式扩展,并且对于具有大型结果集的查询来说成本极高。

无论您请求多少文档,Firestore安全规则都是如此。请阅读并理解本文档。它不允许您有条件地检查每个文档的某些内容,以确定它是否可以读取。您的规则试图表示,对于每次会话读取,匹配的患者文档中必须存在某些内容,但这是不允许的。它无法按Firestore所需的方式扩展,并且对于具有大型结果集的查询来说成本极高。

Firebase安全规则不会对其自身的筛选数据进行扩展,因为这不会扩展。当我们看到:

match /sessions/{document=**} { 
    allow read, write,list: if checkPatientAccess(get(/databases/$(database)/documents/patients/$(resource.data.patientUID)).data);
}
function checkPatientAccess(patient){
  return request.auth.uid in patient.therapistUIDs;
}
为了确保读取操作的安全,这些规则必须加载每个文档并检查其中的
治疗师ID
值。这将是一个O(n)操作,而Firestore保证在O(1)上返回结果。因此,此类安全规则不起作用

您的规则确实适用于阅读单个文档,但不适用于
列表
操作

如果您可以提供一个返回所需数据的查询,那么您就可以保护该查询。但由于Firestore不支持任何类型的加入查询,因此您需要将要筛选的数据从
患者
文档复制到每个
会话
文档中,以实现此功能


如注释中所述:由于您的查询确保所有文档都具有相同的
patientUID
,因此规则中的
get()
调用保证始终获得相同的文档,因此规则引擎可以保证它不会为查询返回授权文档


实际上相当漂亮。

Firebase安全规则不依赖于它们自己的筛选数据,因为这不会扩展。当我们看到:

match /sessions/{document=**} { 
    allow read, write,list: if checkPatientAccess(get(/databases/$(database)/documents/patients/$(resource.data.patientUID)).data);
}
function checkPatientAccess(patient){
  return request.auth.uid in patient.therapistUIDs;
}
为了确保读取操作的安全,这些规则必须加载每个文档并检查其中的
治疗师ID
值。这将是一个O(n)操作,而Firestore保证在O(1)上返回结果。因此,此类安全规则不起作用

您的规则确实适用于阅读单个文档,但不适用于
列表
操作

如果您可以提供一个返回所需数据的查询,那么您就可以保护该查询。但由于Firestore不支持任何类型的加入查询,因此您需要将要筛选的数据从
患者
文档复制到每个
会话
文档中,以实现此功能


如注释中所述:由于您的查询确保所有文档都具有相同的
patientUID
,因此规则中的
get()
调用保证始终获得相同的文档,因此规则引擎可以保证它不会为查询返回授权文档


实际上相当漂亮。

是的,但我只请求我知道存在匹配文档的文档,这样做是否仍然错误?这无关紧要。规则不知道这一点。您不能重写规则的行为。是的,但我只请求我知道存在匹配文档的文档,这样做是否仍然错误?这无关紧要。规则不知道这一点。您无法重写规则的行为。这些规则使用另一个参数工作是否奇怪?比如说,泰德?因为它可以用它来工作。(为患者获取最后一次会话)如前所述:它适用于您正在阅读的文档中的字段,因为规则引擎足够智能,可以在您的侦听器连接时检查这些字段。但它不能对其他文档执行此操作,因为它必须主动检查这些文档。但这是相同的方法、相同的规则、相同的规则流。使用where(“patientUID”,equals:uid)代替where(“therapistUID”,equals:uid)很抱歉再次问你,但对我来说这很奇怪,它应该会给出两个方面的错误。我得到了关于文档的解释,该文档应该存在,不能每次都检查,对此我非常感谢,现在更清楚了。但我没有解释这种态度。你说“(为患者进行最后一次治疗)”,我想这意味着你得到的是一份文件。在这种情况下,规则引擎实际上读取了一个文档,因为它可以保证需要多长时间。请看我答案中的第二段。这些规则使用另一个参数工作是否奇怪?比如说,泰德?因为它可以用它来工作。(为患者获取最后一次会话)如前所述:它适用于您正在阅读的文档中的字段,因为规则引擎足够智能,可以在您的侦听器连接时检查这些字段。但对于其他文档,它不能这样做,因为它必须主动检查这些文档。但这是相同的方法,相同的规则,相同的