I have an app that is designed so authenticated users via Google only have access to their own data with no "social" features. I want to know the security rules for the below criteria.
Let's say I have 5 collections and one of them is called "todos" and the data mirrors the other collections in that it has a field for the authenticated users uid. The typical document looks something like this:
Todos
todo:{
title:"some titled",
body:"we are the world , we are the children",
uid:"2378y4c2378rdt2387btyc23r7y"
}
Some other collection
thing:{
name:"some name",
content:"Some content",
whatever:"whu-eva",
uid:"2378y4c2378rdt2387btyc23r7y"
}
I want the authenticated Google user to be able to CRUD any data that has said users uid in the uid field. I want all other data to be inaccessible to the logged in user.
I want to know how to create rules for this scenario.
I'm mulling through the documentation now but I figure I might be able to save some time by asking. I do not have specific roles for the app. https://firebase.google.com/docs/firestore/solutions/role-based-access
As a side note, is their a feature in Firebase to automatically bind an authenticated Google users uid to documents created while they are logged in? (I am assuming the answer is no and I was planning on manually grabbing the uid in my app and setting it on the client prior to document creation).
Thank you.
Update
I tried using the code that Klugjo posted below.
When I try to test it in the simulator I get an error.
Here is my collection and a screenshot of the error.
Here is something else I tried:
Based on everything I've read it seems like the following code should work - but it doesn't. I've supplemented the key "userId" in place of " uid" that is written in the object data at the top of this post. I changed the key to distinguish it from the uid.
service cloud.firestore {
match /databases/{database}/documents {
match /todos/{id} {
allow read: if request.auth.uid == request.resource.data.userId;
allow create, update, delete:
if request.resource.data.userId == request.auth.uid;
}
}
}
I've created a video where I try to GET and CREATE a document. I don't think I am using the testing feature correctly.
Video
https://www.youtube.com/watch?v=W7GZNxmBCBo&feature=youtu.be
EDIT
I have it working when I test with a hard-coded request.auth.uid
.
In the image below I hardcoded "test" as the request.auth.uid
.
My problem now is that I would really like to know how to test it in the rules editor without hard-coding this information.
Edit
Here is a video demo of the problem using a real app.
https://www.youtube.com/watch?v=J8qctcpKd4Y&feature=youtu.be
Here is a sample secure rule set for your requirements.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{id}/{u=**} {
allow read, write: if (isSignedIn() && isUser(id));
}
match /todos/{id}/{t=**} {
allow read, write: if (isSignedIn() && isUserOwner());
}
match /{document=**} {
allow read, write: if false;
}
function isSignedIn() {
return request.auth != null;
}
function isUser(uid) {
return uid == request.auth.uid;
}
function isUserOwner() {
return getResourceData().uid == request.auth.uid;
}
function getResourceData() {
return resource == null ? request.resource.data : resource.data
}
}
}
All documents are publicly inaccessible.
The rests will be decided based on the data already saved in DB and / or the data being sent by the user. The key point is resource
only exists when reading from DB and request.resource
only exists when writing to DB (reading from the user).
Documents under todos
can be read and written only if they have a saved uid
which is the same as the sent request's uid
.
Documents under users
can be read and written only if their document id is the same as the sent request's uid
.
isSignedIn()
function checks if request is authorised.
isUser(id)
function checks if id matches the authorised request's uid.
isUserOwner()
function checks if document's uid matches the authorised request's uid.
I think what you are looking for is the "resource" parameter in the security rules: https://firebase.google.com/docs/firestore/security/rules-conditions#data_validation
Try something like:
service cloud.firestore {
match /databases/{database}/documents {
match /todos/{id} {
allow read, write: if request.auth.uid == resource.data.userId;
}
}
}
EDIT:
If you change your DB to look like the following:
/users/{userId}/todos/**
then you could allow users to read/write anything under their own document with the following rule:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{uid}/{doc=**} {
allow read, write: if request.auth != null && request.auth.uid == uid;
}
}
}
This would have the advantage of not needing to introspect the contents of the data which I believe might count against your read quota.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With