首页 > 解决方案 > 在处理 Firestore 规则时,我无法检查文档中是否存在字段

问题描述

我正在开发一个包含测验文档的应用程序 Firestore 数据库。每个文档都可能有一个名为 peopleCanAccess 的字符串数组字段。

我想在规则中做什么?如果文档具有此字段 (peopleCanAccess),则 peopleCanAccess 中唯一存在的人可以阅读该文档。如果此字段不存在,则所有经过身份验证的人都可以访问它。

在此处输入图像描述

我试过了:

 function existingData() {
      return resource.data;
    }

 function isAuthenticated() {
      return request.auth != null;
    }

    function getUid() {
      return request.auth.uid;
    }

    function fieldExists(data, field) {
      return !isUndefined(data, field) && !isNull(data, field);
    }

    function isUndefined(data, field) {
      return !data.keys().hasAll([field]);
    }

    function isNull(data, field) {
      return data[field] == null;
    }



 match /quiz/{quizID}{
        allow read : if 
        (isAuthenticated() && existingData().owner == getUid())
        || (isAuthenticated() && !('peopleCanAccess' in existingData().keys()))
        || (isAuthenticated() && getUid() in existingData().peopleCanAccess)
           // !fieldExists(resource.data, 'peopleCanAccess');

        ...

}

这些规则无法正常工作。

示例:ID 为 tcsFStMdplOJSyZsluJBLHeOuJs1 的用户可以访问上图中提到的测验,尽管他未在 peopleCanAccess 字段中列出

询问:

 db.collection("quiz")
                .whereEqualTo("id", quizId)
                .get()
                .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                    @Override
                    public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
                        if (queryDocumentSnapshots.isEmpty()){

                        }else {
                            QuizItem quizItem = queryDocumentSnapshots.getDocuments().get(0).toObject(QuizItem.class);
                            accessedQuiz.postValue(quizItem);
                        }
                    }
                });

标签: androidfirebasegoogle-cloud-firestorefirebase-security

解决方案


最后,我找到了解决方案,

我在 Rules Playground 中检查了规则,并没有发现我的规则有任何问题。它工作正常问题出在我的客户端查询中。我在文档中找到了这个:

在编写查询以检索文档时,请记住安全规则不是过滤器——查询是全部或全部。为了节省您的时间和资源,Cloud Firestore 会根据其潜在结果集而不是所有文档的实际字段值来评估查询。如果查询可能返回客户端无权读取的文档,则整个请求将失败。

注意:您可以将读取规则分解为获取和列出规则。get 规则适用于单个文档的请求,list 规则适用于查询和集合请求。

这里

我是如何解决我的问题的:
1- 打破读写规则:

 match /quiz/{quizID}{
              allow get : if 
              (isAuthenticated() && getUid() in existingData().peopleCanAccess)
              ||
              (isAuthenticated() && !checkIfExistsInKeys(existingData(), 'peopleCanAccess'))

              allow list : if 
              (isAuthenticated() && getUid() == existingData().owner)

              allow create : if (isAuthenticated() && getUid() == existingData().owner);
              allow update : if (isAuthenticated() && getUid() == existingData().owner);
              allow delete : if (isAuthenticated() && getUid() == existingData().owner);
       }

2-更改我的客户查询以检索一个文档:

db.collection("quiz")
                .document(quizId)
                .get()
                .addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
                    @Override
                    public void onSuccess(DocumentSnapshot documentSnapshot) {
                        if (!documentSnapshot.exists()){

                        }else {
                            QuizItem quizItem = documentSnapshot.toObject(QuizItem.class);
                            accessedQuiz.postValue(quizItem);
                        }
                    }
                });

推荐阅读