I want to create a firebase rule that allows users to read and write to child if a property of that child has a specific value. Let's say my database looks something like this:
"tasks": {
"SDkh7s62jnd23d9": {
"uid": "someuserid",
"other": "datagoes here"
}
}
Here is my current security rule:
"tasks": {
".indexOn": "_state",
"$registerQueueKey": {
".read": "data.child('uid').val() == auth.uid",
".write": "newData.child('uid').val() == auth.uid"
}
}
This rule restricts user write permissions, but it never lets a user read, even if the child they are attempting to read has a uid property that equals auth.id.
I then tested the following rule set:
"tasks": {
".indexOn": "_state",
"$registerQueueKey": {
".read": true,
".write": "newData.child('uid').val() == auth.uid"
}
}
Despite the .read permission being set to a permanent true value, the user still cannot read the $registerQueueKey child.
I then tested the following rule set:
"tasks": {
".indexOn": "_state",
".read": true,
"$registerQueueKey": {
".write": "newData.child('uid').val() == auth.uid"
}
}
Now I can read the child fine, so I attempted this final security rule:
"tasks": {
".indexOn": "_state",
".read": "data.child($registerQueueKey").child('uid').val() == auth.uid",
"$registerQueueKey": {
".write": "newData.child('uid').val() == auth.uid"
}
}
But this rule throws an error because the variable $registerQueueKey is undefined in the scope it is being used.
How do I accomplish a rule like this?
I think the error is because you have not placed a wildcard:
"tasks": {
"$uid": {
".indexOn": "_state",
".read": "data.child($registerQueueKey").child('$uid').val() == auth.uid",
"$registerQueueKey": {
".write": "newData.child('$uid').val() == auth.uid"
}
}
}
Related
I want user to only access their own content, except for one child node: common
In common child node I want all signed in users to have access.
I have made the following rules:
{
"rules": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
},
"common" : {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
}
}
Firebase gives me the error:
Error saving rules - Line 8: Unknown variable '$uid'.
The error appears in this line: ".read": "auth != null && auth.uid == $uid",
Based on your question, this is your desired database structure:
{
"userIdA": { // anything here can be written by only userIdA
"name": "Tom", // this is just example data
"location": "London",
/* ... */
},
"userIdB": { // anything here can be written by only userIdB
"name": "Sarah",
"location": "New York",
/* ... */
},
/* ... other user data ... */
"common": { // anything here can be written by signed in users
"data1": "some value",
"data2": "some other value",
}
}
The rules for this structure would be:
{
"rules": {
"common" : {
".read": "auth != null", // logged in users can read
".write": "auth != null" // logged in users can write
},
"$uid": { // $uid will be the value of any key, that isn't listed above it (in this case, anything other than "common")
".read": "$uid === auth.uid", // only the matching user can read
".write": "$uid === auth.uid" // only the matching user can write
}
}
}
Note: This data structure isn't very secure. Allow read/write access to only what you need in your database. With this structure, any user could come along and open up their console and delete everything under "/common". You may consider adding ".validate" rules to make sure certain keys (such as "/common/data1") are only strings.
The $uid must be inside users Document like the example below :
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
I was writing security rules in my database but I do not understand why the validation does not pass it ..
I just want people to be able to type in "Extra" if the key says "nombre".
In case it's not the key "nombre", don't let it.
the rules:
"rules": {
"Users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid && root.child('Users').child(auth.uid).exists() === false || newData.hasChild('Extra')",
".validate": "newData.hasChildren(['nombre'])",
"Extra":{
}
}
}
}
Is the writing rule wrong? Does someone explain to me why?
TEST1 wrong
TEST2
You're writing to location /Users/$uid/Extra, so the nombre property ends up in /Users/$uid/Extra/nombre. To test the rule, you'll want to write to /Users/$uid.
If instead you want to allow the JSON like this:
Users: {
myUserId: {
Extra: {
nombre: "MT Designer"
}
}
}
Then your rules currently don't work, because you're validating that nombre exissts under myUserId. It should be:
{
"rules": {
"Users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid && root.child('Users').child(auth.uid).exists() === false || newData.hasChild('Extra')",
"Extra":{
".validate": "newData.hasChildren(['nombre'])",
}
}
}
}
}
Update: 2020-07-10
From the new screenshots it seems that yyou haven't applied the change from above yet, so I'd first recommend doing that. But if you want to reject other child nodes in Extra, you can do that by changing the rules to:
"Extra":{
"nombre": {
".validate": "data.isString()"
},
"$other": {
".validate": false
},
}
So this validates that the name is a string, and rejects all other child nodes.
From comments, apparently this is what OP ended up with:
"Users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid && root.child('Users').child(auth.uid).exists() === false || newData.hasChild('Extra')",
"$othernode": {
".validate": false
},
"Extra": {
"nombre": {
".validate": "newData.isString()"
},
"$other": {
".validate": false
},
}
}
},
I have my rules set. Normally, all data can only be read by the person who is auth to do so. However, I want to make exceptions. These are my rules:
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid",
"ForEveryone": {
".read": true,
".write": true
}
"NoWrite" : {
".read": true,
".write": false
}
}
}
So I let's say I have 3 string. String 1 is called private and can the auth person can read and write. String 2 is ForEveryone, so everyone can change and write data. String 3 is NoWrite, for everyone but you can not write to it.
I get an error, saying:Expecting a ; or " at the line NoWrite. So what am I doing wrong? Is it a wrong placed }? Thank you.
The approach you're taking to your rule structure won't work. Firebase security rules cascade, meaning that a permission given to any node will apply to any of its children and on down the tree. You cannot grant read or write access on a node and then revoke it further down. (But you can grant permissions not granted above.) See the docs on rule cascading.
In your case, you want to have some user data that be can written to by anyone and some that cannot. It's not clear from your example whether you want NoWrite to be written only by the authenticated user, or by nobody. Depending on how you will be reading this data, you will need to either separate these data into different collections, or make $uid inaccessible and define your rules only for ForEveryone and NoWrite.
The first approach might look like this:
"rules": {
"users-public": {
"$uid": {
".read": "true",
".write": "true",
},
"users-nowrite": {
"$uid": {
".read": "true",
".write": "$uid === auth.uid"
}
}
Or the second, like this:
"rules": {
"users": {
"$uid": {
"ForEveryone": {
".read": "true",
".write": "true"
},
"NoWrite" : {
".read": "true",
".write": "$uid === auth.uid"
}
}
}
As to your syntax error, you need a comma , after the closing brace before "NoWrite".
Here are your rules, properly spaced so you can see the relationship between the parent nodes and child nodes. It seems this is not what you want. So this isn't really an answer but will lead to a better question that we can answer. Will update once we know what the OP is after.
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid",
"ForEveryone": {
".read": true,
".write": true
},
"NoWrite" : {
".read": true,
".write": false
}
} //end uid
} //end users
} //end rules
} //outside closure
I'm trying to set users to get only own objects. I have a tasks which have 3 attributes on fb-database: task-text, datetime, user. user have user uid. I want to write a rule that allow user to read only own tasks.
So far I have this and it dont work:
{
"rules": {
"tasks": {
".read": "auth.uid == data.child('user').val()",
".write": "auth.uid != null",
}
}
}
You'll want to break up the tasks by user, so you'll have a structure that looks like:
root
tasks
Puf
...
Andrew
...
James
...
This can be secured via rules that look like:
{
"rules": {
"tasks": {
"$userId": {
".read": "auth.uid == $userId",
".write": "auth.uid == $userId",
}
}
}
}
The following are my Firebase security rules:
security-rules.json
{
"rules": {
"users": {
"$uid": {
".write": "auth.uid === $uid",
".read": "auth.uid === $uid"
}
}
}
}
It works fine when my path ends with the users directory. As in:
https://my-firebase.firebaseio.com/users/my-user-id.json
But when I try to post directly to a subdirectory, as follows:
https://my-firebase.firebaseio.com/users/my-user-id/settings.json
it doesn't work.
Question
What do I need to do to the security-rules.json file (or anything else) to be able to write directly to a user's subdirectory?
Edit:
Someone suggested, "just extend your rule to include settings." So I tried this:
security-rules.json
{
"rules": {
"users": {
"$uid": {
".write": "auth.uid === $uid",
".read": "auth.uid === $uid"
},
"settings": {
".write": "auth.uid === $uid",
".read": "auth.uid === $uid"
}
}
}
}
Which throws the following error:
9:30: Unknown variable '$uid'.
10:31: Unknown variable '$uid'.
This works in the simulator:
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
"settings": {
}
}
}
}
}
After further testing, I found the security rules contained in the OP also work in the simulator:
security-rules.json
{
"rules": {
"users": {
"$uid": {
".write": "auth.uid === $uid",
".read": "auth.uid === $uid"
}
}
}
}
There is no need to add additional rules for writing deeper into the node tree. The highest level permissions are sufficient.
Aside: My problem appears to be something other than the security rules I'm using. I must do more research, experimentation and testing.