This is my DB:
Each key was created by combining the user name. I want to make sure that only the members within each piece of data are accessible.
{
"rules": {
"chatroom": {
".write": "auth != null",
"$room_id": {
".read": "$room_id.contains(auth.uid)"
}
}
}
}
Since each key was created by combining the user name,
I thought I could use this .contains
function to limit who can access it.
In Flutter,
lastQuery = db.ref('chatroom').orderByChild('date');
data = await lastQuery.limitToLast(10).once();
But occurred Error:
[firebase_database/permission-denied] Client doesn't have permission to access the desired data.
With all allowed rules, this code works fine. For example,
{
"rules": {
".read": "true",
".write": "true"
}
}
{
"rules": {
"chatroom": {
".write": "auth != null",
"$room_id": {
".read": "data.child('member').child(auth.uid).val() == true",
}
}
}
}
Try this rules, Because key, value in member, it is made of UID : Bool.
This also causes an error.
What should I do?
Firebase's security rules don't filter data. Rather they merely ensure that the code is only trying to read data that it is allowed to access.
That's why the code and rules always go hand-in-hand: the code must request exactly the nodes that you want it to be able to read, and then the rules must ensure that only those requests are allowed.
So when you do this in your code:
lastQuery = db.ref('chatroom').orderByChild('date');
data = await lastQuery.limitToLast(10).once();
The rules engine checks if the user has read permission on the chatroom
node. And since there's no .read
clause on that node or above it, the operation gets rejected.
While you can define a condition for a query in your rules, those won't work here - as you can't mimic the contains
operation from the rules in your actual code.
The idiomatic approach is to create an additional top-level node where you track the chatroom IDs that each user has access to. So something like:
userChatrooms: {
"$uid1": {
"$chatroomId1": true,
"$chatroomId2": true
},
"$uid2": {
"$chatroomId1": true,
"$chatroomId3": true
},
"$uid3" {
"$chatroomId2": true,
"$chatroomId3": true
}
}
With such a structure in place, you can:
/userChatrooms/$uid
. It's also easy to secure this structure with owner-only access./chatroom/$chatroomID
. Now your current rules work, since you no longer need to read the while root chatroom
node, and you've already sufficiently secured access to the individual rooms with your current rules.