Firebase规则表现得非常奇怪
大家好,读到这篇文章的人 我正在为一家医院编写一个颤振应用程序,它具有这种db结构 我在获取会话数据时遇到问题,正是以下文档 使用以下方法获取治疗师进行的最后一次治疗,使用他的治疗师ID作为过滤字段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
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)很抱歉再次问你,但对我来说这很奇怪,它应该会给出两个方面的错误。我得到了关于文档的解释,该文档应该存在,不能每次都检查,对此我非常感谢,现在更清楚了。但我没有解释这种态度。你说“(为患者进行最后一次治疗)”,我想这意味着你得到的是一份文件。在这种情况下,规则引擎实际上读取了一个文档,因为它可以保证需要多长时间。请看我答案中的第二段。这些规则使用另一个参数工作是否奇怪?比如说,泰德?因为它可以用它来工作。(为患者获取最后一次会话)如前所述:它适用于您正在阅读的文档中的字段,因为规则引擎足够智能,可以在您的侦听器连接时检查这些字段。但对于其他文档,它不能这样做,因为它必须主动检查这些文档。但这是相同的方法,相同的规则,相同的