I'm trying to implement a role based access control using reactjs and firebase. My plan is to use the built-in authentication methods (email and password and google auth). The uuid will be saved in a collection called users
.
I won't be using custom claims since I'll be storing a lot of data in users
collection i.e profile picture, username, first name,last name etc.
So along with all this data I'm going to store another property called isAdmin
which will be boolean value.
My users will be able to
My admin will be able to:
Anyone not signed in will be able to:
This is the rules that I have written so far:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow create
allow read
allow write: if request.auth.uid == userId || request.auth.token.isAdmin == true
}
match /posts/{postId}{
allow read
}
match /collection/{collectionId}{
allow read
}
}
}
I've no idea if I can make public/private using firebase and if any of my rule is correct. Need some insight.
Update 1: This is my re-written rules for firestore:
service cloud.firestore {
match /databases/{database}/documents {
function isPublic(){
return resource.data.visibility == "public";
}
function isAdmin() {
return request.auth.token.role == "admin";
}
function isUser(userId) {
return request.auth.token.role == "user" && request.auth.uid == userId;
}
match /posts/{post} {
allow write: if isAdmin() || isUser(userId); // only admins and users themselves can write
allow read: if isPublic(); // any body can read if the visibility is public
}
match /users/{userId}{
allow read: if true; // anyone can see a user
allow write: if isAdmin() || isUser(userId); // only the user themselves or the admins can write
}
}
}
As mentioned above only the user who created a post will be able to write his/her own post so I guessed I'll need to pass the userId
as well but the line: allow write: if isAdmin() || isUser(userId);
is throwing in errors. How can I pass the postId
and the userId
at the same time to the match function?
This is what I came up with. Up until now everything works fine, I'll change the answer if I see any problem as soon as I created my frontend.
I've also provided comments for better understanding:
service cloud.firestore {
match /databases/{database}/documents {
// anyone can view the user
// only the user who created the account and admin can edit accout
// only the user who created the account and admin can delete accout
match /users/{userId}{
allow create: if true
allow read: if true
allow write: if request.auth.uid == userId // check for admin
allow delete: if request.auth.uid == userId // check for admin
}
// anyone can view the link if it's public
// only the author of the link and admin can edit/update/delete the link
match /posts/{postId} {
allow create: if request.auth.uid != null
allow read: if true && request.resource.data.visibility == "public"
allow write: if request.resource.data.author_id == request.auth.uid // check for admin
allow delete: if request.resource.data.author_id == request.auth.uid // check for admin
}
// anyone can view the collection if it's public
// only the author of the link and admin can edit/update/delete the collection
match /collections/{collectionId}{
allow create: if request.auth.uid != null
allow read: if true && request.resource.data.visibility == "public"
allow write: if request.resource.data.author_id == request.auth.uid // check for admin
allow delete: if request.resource.data.author_id == request.auth.uid // check for admin
}
}
}
Update: After testing the rules work. I strongly advise anyone who want to take help from this answer create individual functions like isAdmin()
and isOwner()
etc. Clears a lot of the clutter