Я не могу проверить, существует ли поле в документе при работе над правилами пожарного депо - PullRequest
0 голосов
/ 18 марта 2020

Я работаю над базой данных 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 Ответ

1 голос
/ 19 марта 2020

Наконец-то я нашел решение,

Я проверил правила в 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);
                        }
                    }
                });
...