It is unclear what the value of $key
is expected to be. So I'm going to assume it's just some random string that isn't used in the rules.
For each security rule, the current data of the node is accessible using the predefined variable data
. ".write"
and ".validate"
rules also have access to the to-be-written data as newData
. These are both RuleDataSnapshot objects.
Assuming that a user making changes must be the user given by the uid
property, the following rules can be used.
"rules": {
"users": {
"$key": {
".read": "auth != null && data.child('uid').val() == auth.uid",
".write": "auth != null && ((data.exists() && data.child('uid').val() == auth.uid) || (!data.exists() && newData.child('uid').val() == auth.uid)"
}
}
}
The above rules use a fail-fast approach. If a user is not logged in, the check aborts. Otherwise, the user's ID is matched against the existing data at the given node. If the data doesn't yet exist, the newly updated data must also match the current user's ID.
In case the "cafe" role is important, the following rules also require that the "cafe" is set to true
to allow read/write operations.
"rules": {
"users": {
"$key": {
".read": "auth != null && data.child('uid').val() == auth.uid && data.child('role/cafe').val() == true",
".write": "auth != null && ((data.exists() && data.child('uid').val() == auth.uid && data.child('role/cafe').val() == true) || (!data.exists() && newData.child('uid').val() == auth.uid && newData.child('role/cafe') == true))"
}
}
}
Note: If $key
is storing user info/data, I highly recommend using the user's ID as the key as security rules cannot perform queries like "does userid have admin role?" without structuring your data to allow it. If $key
is meant to be a username, instead use a username-to-userID map as it will prevent future problems. One such example is if a user wants to change their username, you can remove and link the new username to the user without ever having to move all their data.
$key
? How do you get the value of$key
when you want to look up a user's data (such as in another rule)? For these reasons, I highly recommend against making it anything other than the user ID and using lookup indexes (e.g. username: uid). – samthecodingman