I'm trying to have a data structure like this and to ensure that a user can only pull in their own data, since all the processing is done client side.
What database security rules would I have to use so that User1 can access their own posts, but cannot access User2's posts?
(I'm using Firebase web)
Sample database structure:
{
"posts" : {
"001" : {
"text" : "note 1",
"userID" : "User1"
},
"002" : {
"text" : "note 2",
"userID" : "User1"
},
"003" : {
"text" : "note 3",
"userID" : "User2"
}
}
}
Sample database query:
firebase.database().ref('/posts/').once('value').then(function(snapshot) {
console.log(snapshot.val()); // Returns all 3 posts
});
In your current structure it is very easy to secure data access to each post's creator:
{
"rules": {
"posts": {
"$postid": {
".read": "data.child('userID').val() === auth.uid"
}
}
}
}
This is all that is needed: now each user can only read their own posts.
But there is one big problem with this approach: no-one can now read from /posts
, so no-one can get a list of all posts.
And to grant someone the ability to list posts, you must give them read access to /posts
. And since you cannot revoke a permission on a lower level, that means that you at that point they can read all posts, not just the ones they created.
This is known within Firebase as rules are not filters: you cannot use rules to filter data. We've covered it quite a bit here on Stack Overflow, so I recommend you also check out some other questions on the topic.
There are quite a few solutions to the problem.
A common solution is to create a list of the post IDs that each user has access to. This is often called a (secondary) index and adds this additional data to your model:
{
"userPosts" : {
"User1": {
"001" : true,
"002" : true
},
"User2": {
"003" : true
}
}
}
Now you secure access to the original posts as before, but then secure access to the secondary index with:
{
"rules": {
"userPosts": {
"$userid": {
".read": "$userid === auth.uid"
}
}
}
}
So each user can read the list of postIDs they have access to, and can then read each individual post under /posts/postID
.
In your case, there is a simpler solution. I'd model that data slightly more hierarchical, with each user's posts under their own UID:
{
"posts" : {
"User1": {
"001" : {
"text" : "note 1",
"userID" : "User1"
},
"002" : {
"text" : "note 2",
"userID" : "User1"
},
},
"User2": {
"003" : {
"text" : "note 3",
"userID" : "User2"
}
}
}
}
Now you can secure access with:
{
"rules": {
"posts": {
"$userid": {
".read": "$userid === auth.uid"
}
}
}
}
And each user can read and list their own posts. But do keep the secondary index in mind, since you're likely to need it sooner or later.
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