I am having trouble implementing a role-based access system using Firestore rules and Vuexfire.
My goal is to be able to bind a list in my app to a Firestore collection, with only part of its elements visible / editable, based on user roles.
When attempting that with my current structure, giving a read/write access to a single element in the collection returns an "insufficient permissions" error when binding the collection and nothing is retrieved.
The behaviour I am trying to achieve is :
- When accessing the list in my app, the user will only see the elements his roles collection grant him access to.
- An empty list should only occur if either the collection is empty, or the user has no relevant role over any element in the collection.
The current structure can be illustrated as follows :
hotels/
hotelA
name: "hotel-a"
rooms/
roomA
roomB
hotelB
name: "hotel-b"
rooms/
users/
adminA
roles/
hotelA
role: "admin"
Using the following rules :
service cloud.firestore {
match /databases/{database}/documents {
allow read: if request.auth != null;
match /hotels/{hotel} {
function isSignedIn() {
return request.auth != null;
}
function getRole(rsc) {
return get(/databases/$(database)/documents/users/$(request.auth.uid)/roles/$(rsc.id)).data.role;
}
function isOneOfRoles(rsc, array) {
return isSignedIn() && (getRole(rsc) in array);
}
allow read, write: if isOneOfRoles(resource, ["admin"]);
}
}
}
I then use Vuexfire to bind a list of hotels to the hotels collection, like so :
const setListHotelRefFromId = (context) => {
var db = firebase.firestore()
var listHotelRef = db.collection('hotels')
context.dispatch('setListHotelRef', { ref: listHotelRef })
}
const setListHotelRef = firebaseAction(({ bindFirebaseRef, unbindFirebaseRef, commit }, { ref }) => {
commit(types.SET_LOADING, true)
bindFirebaseRef('list.hotel', ref).then(() => {
commit(types.SET_LOADING, false)
})
})
In the environment described above, suppose I log in as a user whose userID is "AdminA", and access the hotel list. I would be expecting to see a list with a single entry, "hotelA", but instead get an "insufficient permissions" error from Firestore.