1
votes

I have a Firestore collection structured like this: /database/{database}/documents/group/{group}/...

Each group has a field named "members" that is an array of userIDs:

group: {
    members: [
        "user01",
        "user02",
    ]
}

I have an iOS (Swift) snapshot listener on this collection:

Firestore.firestore().collection("group").whereField("members", arrayContains: Auth.auth().currentUser.uid)
            .addSnapshotListener {...

Which works if I leave the Firestore Rules mostly open with:

match /group/{group}/{document=**} {
    allow read: if request.auth.uid != null;
}

However, when I try to secure the collection to only allow the above snapshot (and not a request to other documents in the collection), my permissions are not correct. This is what I have tried:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /group/{group}/{document=**} {
      allow read: if request.auth.uid in get(/database/$(database)/documents/group/$(group)).data.members || request.auth.uid in get(/database/$(database)/documents/group/$(group)).members;
    }
  }
}

I have also tried:

match /group/{group} {
    allow read: if request.auth.uid in resource.data.members;
}

Which appears to work, but does not allow me to access child collections of the document. I need the get() rules method to work.

Similar solutions seem to have worked for others on SO. Is there another way to allow this type of permission on a document and child collections or perhaps I am overlooking something obvious with this solution?


EDIT

After reading through more docs, it appears that this solution works:

match /group/{group} {
    allow read: if request.auth.uid in resource.data.members;
    match /child_collection/{document=**} {
        allow read: if request.auth != null;
    }
}

I'll give some time before I list that as the answer in case anyone more experienced has a better solution.

1

1 Answers

1
votes

After reading through more docs, it appears that this solution works:

match /group/{group} {
    allow read: if request.auth.uid in resource.data.members;
    match /child_collection/{document=**} {
        allow read: if request.auth != null;
    }
}

If anyone has input on a solution using get(), that would be very helpful as well!