jhbiggs
jhbiggs

Reputation: 88

Cloud Firestore Security Rules give null for resource.data in production code

I am working on an app for education that gives teachers access to student assignment documents based on a common subject. I have set a custom claim client-side for the teacher and set documents with a common field, "subject". My rule looks like this:

    match /assignments/{entry} {

        allow read: if isSignedIn() && resource.data.subject == request.auth.token.subject;
        allow write: if request.auth.token.moderator == true;


    //TODO: assignment rules go here
    function isSignedIn() {
    return request.auth.uid != null;
    }
        
    }
  }

Despite everything I cannot get the resource to pull any data. Even resource.data != null displays false.

My custom claims come through fine and request.auth.token.subject == "Biology" displays true for my example account.

Here is the query:

_guestBookSubscription = FirebaseFirestore.instance
            .collection('assignments')
            .orderBy('start_date', descending: true)
            .limit(30)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          for (final document in snapshot.docs) {
            _guestBookMessages.add(RTIAssignment(
              // endDate: (document.data()['end_date'] as DateTime),
              standard: document.data()['standard'] as String,
              startDate: DateTime.now(), // (document.data()['start_date']),
              student: Student(name: document.data()['student_name']),
              subject: document.data()['subject'] as String,
              teacher: document.data()['name'] as String,
            ));
          }
          notifyListeners();
        });

It's from the nifty codelabs on writing queries that Google puts out.

I'm not sure how to copy in the target document for the query. It's in Firebase and one of the fields is "subject".

Upvotes: 1

Views: 499

Answers (1)

Mises
Mises

Reputation: 4603

Firestore rules are not for sorting data you can download and cannot download. You probably query data with no where() method/function included. Firestore thinks you want to query all documents so he reject whole query.

Include in your query:

JavaScript

const q = query(citiesRef, where("subject", "==", "Biology"));
...

or

db.collection("cities").whereField("subject", isEqualTo: "Biology")

Probobly second .whereField() method will work with flutter but i don't know.

This is how rules should looks like:

match /databases/{database}/documents {
    match /{document=**} { // here you restrict access to whole database
      allow read, write: if false;
    }
    match /assignments/{docID} { // here except data to whole database was restricted you allow to read write documents in this collection path.
        allow read: if isTeacher() || isModerator()
        allow write: if isModerator()
    }
    function isTeacher() {
        return request.auth.token.subject == resource.data.subject
    }
    function isModerator() {
        return request.auth.token.moderator == true;
    }
  }

Teachers with token.subject == "Biology" can only request documents with field subject == "Biology" so they need to use whereField() in query. If teacher subject is "Math" he need to request only documents whereField("subject", isEqualTo: "Math") Moderators no need to use "whereField()" they can read whole data.

Upvotes: 1

Related Questions