使用Firestore规则时,我无法检查文档中是否存在字段

时间:2020-03-18 12:24:33

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

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

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

enter image description here

我尝试过:

 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');

        ...

}

这些规则无法正常工作。

示例: 身份为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);
                        }
                    }
                });

1 个答案:

答案 0 :(得分:1)

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

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

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

注意:您可以将读取规则分为get和list规则。获取规则 适用于单个文件的请求,而列表规则适用于 查询和索取要求。

here

我如何解决我的问题:
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);
                        }
                    }
                });