Rahul Raj Sonu
Rahul Raj Sonu

Reputation: 103

Let user access to their own data in firebase

I have user associated with each data,

data model pic

and rule defines as below-

{
  "rules": {
    ".read": false,
    ".write": false,
    "expenses": {
      ".read": "auth.uid === data.child('userId').val()",
      ".write": "auth.uid === data.child('userId').val()"
    },
    "categories": {
        ".read": "auth != null",
        ".write": "auth != null"
    }
  }
}

I have a requirement that the user can only read the data where their userId is associated.

function to get Data-

getExpense():AngularFireList<ExpenseData>{
   if (!this.userId) return;
   this.expenses = this.db.list(`expenses`);
   return this.expenses
}



getCategory():AngularFireList<CategoryData>{
   if (!this.userId) return;
   this.categories = this.db.list('categories');
   return this.categories;
}

Error:

ERROR Error: permission_denied at /expenses: Client doesn't have permission to access the desired data.

Upvotes: 0

Views: 1474

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

It looks like you're trying to read from /expenses, but this is the condition to get access to /expenses:

".read": "auth.uid === data.child('userId').val()",

Since there is no /expenses/userId, nobody has access to /expenses. If you add a /expenses/userId with a UID, then the user with that UID will have access to all of /expenses, not just their own.

Note that security rules can't be used to filter data, which I think you're trying to do. This topic has been covered a lot before, so I recommend you check out a few of the questions that mention "rules are not filters".

Since a few months it is possible to accomplish your scenario. But you will need to do this as two steps that go hand-in-hand:

  1. From your code make sure to query only the child nodes that are allowed.
  2. Use your rules to validate that the query is only accessing data that is allowed.

See the documentation on query-based rules. From there:

The code:

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)     

The rules:

"baskets": {
  ".read": "auth.uid != null &&
            query.orderByChild == 'owner' &&
            query.equalTo == auth.uid" // restrict basket access to owner of basket
}

Upvotes: 2

Related Questions