Reputation: 29683
In continuation to my previous question I have below design for my application.
Design
Here is how I add the data through my android application.
FirebaseInstance mFirebaseInstance = FirebaseDatabase.getInstance();
FirebaseDatabase mFirebaseDatabase = mFirebaseInstance.getReference("tbl-customers").child(FirebaseAuth.getInstance().getCurrentUser().getUid());
//This will create or fetch user id node under tbl-customers.
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String name = inputName.getText().toString();
String email = inputCode.getText().toString();
String limit= inputLimit.getText().toString();
createUser(name, email,limit);
}
});
private void createUser(String name, String email,String limit) {
userId = mFirebaseDatabase.push().getKey();
Customer customer = new Customer(name, email,limit);
mFirebaseDatabase.child(userId).setValue(customer);
}
That's it.. In Database it is somehow represented as below:
tbl-customers
|___loggedInUserId1
|___customerID1
|___customerName
|___customerCode
|___customerLimit
|___customerID2
|___customerName
|___customerCode
|___customerLimit
|___customerID3
|___customerName
|___customerCode
|___customerLimit
|___loggedInUserId2
|___customerID4
|___customerName
|___customerCode
|___customerLimit
and I have rules defined as
{
"rules": {
"tbl-customers": {
".read": "auth != null",
".write": "auth != null",
"$custId": {
"customerName": {
".validate": "newData.isString() && newData.val().length < 100 && newData.val().length > 8"
},
"customerCode": {
".validate": "newData.isString() && newData.val().length<4 && !newData.exists() && newData.val().length>1"
},
"customerLimit": {}
}
}
}
}
Unfortunately, the data is inserted without considering any of the validation written for each properties. Even the empty data gets inserted.
I started thinking whether the rule written is of proper structure, because if I see the data inserted then it has 3 levels - tbl-customer-->loggedInUserId-->customerId
but rules have been only written for tbl-customer-->customerId
.
So I changed the rules
as below.
{
"rules": {
"tbl-customers": {
".read": "auth != null",
".write": "auth != null",
"$user_id": {
".validate": "auth.uid===$user_id",
"$custId": {
"customerName": {
".validate": "newData.isString() && newData.val().length < 100"
},
"customerCode": {
".validate": "newData.isString() && newData.val().length<4 && !newData.exists()"
},
"customerLimit": {}
}
}
}
}
}
extending it to one more level by including,
"$user_id": {
".validate": "auth.uid===$user_id"
...
}
But now this throws Permission Denied
Exception. Am out of ideas at this point of time. Could someone guide me in the right direction? I have referred lot of posts from my previous question but to my bad, I couldn't grab much information from it. Hope to find some clear explanation as on why rules validation are failing and why data gets inserted with above mentioned first rule.
Upvotes: 0
Views: 1260
Reputation: 926
I might be wrong here, but the .read and .write rules will always cascade down your tree regardless here, which the line ".write": "auth != null" is most likely where you're facing the problems.
It would be best to move this rule to where the ".validate": "auth.uid===$user_id" rule is and remove the validate rule. You would then change it to something like "auth.uid == $user_id". The 'validate' rule I believe is just for taking in a written input at that specific location and then accepting or rejecting.
This is how I believe it should look:
{
"rules": {
"tbl-customers": {
".read": "auth != null"
"$user_id": {
".write": "auth.uid === $user_id"
"$custId": {
"customerName": {
".validate": "newData.isString() && newData.val().length < 100"
},
"customerCode": {
".validate": "newData.isString() && newData.val().length<4 && !newData.exists()"
},
"customerLimit": {}
}
}
}
}
}
This structure will allow all logged in users to read the data, which you could restrict further to the $user_id location if you wish, similar to the write rule currently in place. This would then only allow users who match the $user_id read and write privileges.
CASE STUDY
To add to this, this is a structure I set up sometime ago that would allow an administrator the ability to add users:
{
"rules": {
"Administrator": {
".read": "auth != null"
},
"Users": {
"$user_id": {
".write": "$user_id === auth.uid",
".read": "$user_id === auth.uid"
}
}
}
}
Upvotes: 2