I am using @angular/fire and I have a temples collection with below schema:
{
name: 'Sri Chamundeshwari temple',
address: 'Chamundi hills, Mysore',
roles: {
'owner@gmail.com': 'owner',
'admin@gmail.com': 'admin',
'member@gmail.com': 'member',
'viewer@gmail.com': 'viewer'
}
}
I want only the 4 users in the roles object to be able to access the temple document. Other users should be denied access.
I followed the guide in this link: https://firebase.google.com/docs/firestore/solutions/role-based-access and structured my security rules as below:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /temples/{temple} {
function isSignedIn() {
return request.auth != null;
}
function getRole(rsc) {
return rsc.data.roles[request.auth.token.email];
}
function isOneOfRoles(rsc, array) {
return isSignedIn() && getRole(rsc) in array;
}
allow read: if isOneOfRoles(resource, ['owner', 'admin', 'member', 'viewer']);
}
}
}
How should I write a suitable query to get all temple documents which is accessible to logged in user?
The guide does not describe anything about queries.
I tried the below queries and they are giving permission errors.
ERROR FirebaseError: Missing or insufficient permissions.
Let's assume there are 10 temples in the collection.
User A has a role as viewer in 3 temples.
I am expecting that the below queries should return only 3 temples accessible to user A.
const q = query(
collectionGroup(this.fireStore, "temples"),
where(`roles.${this.auth.currentUser?.email}`, 'array-contains', ['owner', 'administrator', 'member', 'viewer'])
);
const q = query(
collection(this.fireStore, "temples"),
where(`roles.${this.auth.currentUser?.email}`, 'array-contains', ['owner', 'administrator', 'member', 'viewer'])
);
Update: As per @Frank van Puffelen's answer, replaced the array-contains
with in
operator because in
is the right one to use in this scenario and still receiving permission errors.
You're using the array-contains
operator on the roles.${this.auth.currentUser?.email}
, but that field isn't an array.
To filter in whether a non-array field has one of a number of values, use the in
operator.
As discussed in the comments, you'll need to use FieldPath
as you have a .
in your actual field name (which Firestore will otherwise interpret as a separator).
Roles array in security rules contains admin
and in query contains administrator
. Roles value in query can only be a sub-set of the roles array in security rules.