2

I'm using Redux-Saga as a middle-ware. I'm passing a parameter via query to Firebase Database, but not able to access it on the Database end.

Query:::

database.ref("workouts")
.child(userId)
.once("value")
.then(snapshot => {
 console.log("onSuccess:", snapshot.ref, snapshot.val());
 resolve(snapshot.val());
 })
.catch(function(error) {
 console.log("Error fetching document: ", error);
 reject(error);
 });

UserId is a value I'm fetching from localStorage and sending to database via query using ".child(userId)"

Query::: (For Admin)

database.ref("workouts")
.once("value")
.then(snapshot => {
 console.log("onSuccess:", snapshot.ref, snapshot.val());
 resolve(snapshot.val());
 })
.catch(function(error) {
 console.log("Error fetching document: ", error);
 reject(error);
 });

Rules in database::::

{
"rules": {
         "workouts": {
          // grants write access to the owner of this user account || the user role is equal to  admin
          // grants read access to the owner of this user account || the user role is equal to  admin
".read":"(data.exists() && auth.uid != null && data.child(auth.uid).exists()) ||root.child('users').child(auth.uid).child('role').val() == 'admin'",
".write":"data.exists() ||root.child('users').child(auth.uid).child('role').val() == 'admin'"
                     }
         }
}

I've tried [query.equalTo] and [data.child(auth.uid).val()] methods to access the value, but didn't got any result.

JSON for Workouts:::::

"workouts" : {
"6OiasllKwVSjjRfrCarMAjhkKAH2" : {
  "-LD3nNIKw9Yk3HcoAL0-" : {
         "exercises" : [ {
          "muscleGroup" : "Chest",
          "name" : "Incline Dumbbell Fly",
          "sets" : [ 0, 0, 0, 0, 0 ],
          "type" : "reps"
        } ],
        "name" : "Force Set",
        "reps" : [ "5", "5", "5", "5", "5" ],
        "type" : "Weights"
       }]
    },
    "workoutName" : "My Test workout"
  }

JSON for users:::::

 "users" : {
     "6OiasllKwVSjjRfrCarMAjhkKAH2" : {
     "email" : "testuser@gmail.com",
     "role" : "user",
     "uid" : "6OiasllKwVSjjRfrCarMAjhkKAH2"
       }
     }

Any kind of help is highly appreciated.

Thank you so much in Advance.

Edit:::: Added the query for admin. I want to fetch all the available data in the collection in the case of admin.

  • "I've tried [query.equalTo] and [data.child(auth.uid).val()] methods to access the value, but didn't got any result." That won't work, since you're not performing a query. Can you update your question to include the JSON under `/workouts/$uid` and `/users/$uid` (as text, no screenshots)? You can get this by clicking the "Export JSON" link in your [Firebase Database console](https://console.firebase.google.com/project/_/database/data). – Frank van Puffelen Jun 28 '18 at 13:08

1 Answers1

4

I think I see what's going wrong. Your JSON seems to have all workouts for a user, under /workouts/$uid. Your rules try to give the user access to all of /workouts, instead of just their own.

The solution is to move the rule one level lower into the tree:

{
  "rules": {
    "workouts": {
      // grants access to the owner of this user account || the user role is equal to  admin
      "$uid": {
        ".read":"auth.uid == $uid || root.child('users').child(auth.uid).child('role').val() == 'admin'",
      },
      ".write":"data.exists() || root.child('users').child(auth.uid).child('role').val() == 'admin'"
    }
  }
}

Also see the documentation on securing user data, which has a good simple sample of this.

Update: if you want to allow the admin to read /workouts and each user to be able to read their own workouts under /workouts/$uid, then you need these rules:

{
  "rules": {
    "workouts": {
      // grants access to the owner of this user account
      "$uid": {
        "read": "auth.uid == $uid",
      },
      // grants access to the admin
      ".read": "root.child('users').child(auth.uid).child('role').val() == 'admin'",
      ".write": "data.exists() || root.child('users').child(auth.uid).child('role').val() == 'admin'"
    }
  }
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • First of all thank you Frank for giving your valuable time. I've tried the same thing but this will break in the OR condition. As I also need to provide access to the admin for the same. – Sumit Khatri Jun 28 '18 at 13:24
  • Hi Frank is there any way We can extract the value passed in 'child()' other than using '$ variables '? – VishAl Jun 28 '18 at 13:38
  • 1
    @SumitKhatri Can't you keep the admin rule the same as in your question and use the user rule as in this answer? – André Kool Jun 28 '18 at 13:43
  • The `.read` condition should do precisely what you want. What breaks? – Frank van Puffelen Jun 28 '18 at 14:10
  • Please check the updated question. I've added the query for admin too. – Sumit Khatri Jun 29 '18 at 05:00
  • @FrankvanPuffelen I also want to fetch the data for admin and in that case it will be entire collection. So basically we don't need any restriction in the case of admin. Still I've tried with this one it works for user but for admin it shows this error Error fetching document: Error: permission_denied at /workouts: Client doesn't have permission to access the desired data. – Sumit Khatri Jun 29 '18 at 05:01
  • That makes sense, since with those rules nobody has access to `/workouts`. I updated my answer to match with the new info. – Frank van Puffelen Jun 29 '18 at 14:15
  • Thank you so much @FrankvanPuffelen. – Sumit Khatri Jul 03 '18 at 05:03