1
votes

I've got a Document structure where I have a collection of accounts (_accounts), and each account document in the collection has a subcollection called allowedusers. The documents within allowedusers has a document of each user that has access to the account. Each account document also has field of an array of string of the userids which I'm using to query using Array Contains.

My Firestore rules to ensure that each read is checked against the allowed users is :

match /_accounts/{accountid}{
        allow read: if request.auth != null && get(/databases/$(database)/documents/_accounts/$(accountid)/allowedusers/$(request.auth.uid)).data.allowed == true
    }

Dart Code from Flutter:

QuerySnapshot querySnapshot = await firestore.collection('_accounts').getAccounts()
   .where('userids', arrayContains: _user.id)
   .getDocuments();

The above query is producing a Permission Denied :

PlatformException (PlatformException(Error performing getDocuments, PERMISSION_DENIED: Missing or insufficient permissions., null))

Alternate methods that I've attempted:

Security Rule :

match /_accounts/{accountid}{
        allow read: if request.auth != null && resource.data.userids == request.auth.uid
      
    }

Dart Code:

QuerySnapshot querySnapshot = await firestore.collection('_accounts')
   .where('userids', arrayContains: _user.id)
   .limit(5)
   .getDocuments();

For testing purposes I've only got two documents in the _accounts collection, so I'm assuming that the permission denied is coming from hitting the limits when using get within the security rules.

Is there a way of applying security rule and query the collection like this ?

1

1 Answers

0
votes

The first security rule is rejecting the query because security rules are not filters. Read more about what that means. It's important to understand this concept, so be sure to read and understand the documentation.

Security rules will only allow a query if it can determine that the query will only find documents that are allowed. It will not check each individual document in the collection for permission and filter out the ones that don't pass the rules. That would not scale at all.

The second rule is rejecting access because it's not correctly checking the array field. If userids is an array field, you can't use an equality expression to compare it with a string as you are with resource.data.userids == request.auth.uid.

If you want to make sure that the user's UID is contained within a document, you will need to treat the field like a list object, and use list operations on it. Use hasAny for that.

allow read: if request.auth != null && resource.data.userids.hasAny([request.auth.uid]);