". read" firebase security rules

Asked

Viewed 551 times

9

I created the following security structure in Realtime Database:

{
  "rules": {
    "receita": {
      "$chave": { 
        ".write": "auth.uid === newData.child('usuario').val()",
        ".read": "auth.uid === data.child('usuario').val() || data.child('tipo').val() === true"
      }
    }
  }
}

For the following database structure:

{
  "receita" : {
    "-L92JgTg4xIDCymtq26h" : {
      "imagem" : "default",
      "ingrediente" : [ "teste" ],
      "nome" : "teste",
      "preparo" : "teste",
      "tipo" : true,
      "usuario" : "Az2Mra1xJwXtpaspGwgvj7hm9NA2"
    },
    "-L9CwBmuVETG5TSjLHz7" : {
      "imagem" : "default",
      "ingrediente" : [ "teste" ],
      "nome" : "teste",
      "preparo" : "teste",
      "tipo" : true,
      "usuario" : "Az2Mra1xJwXtpaspGwgvj7hm9NA2"
    }
  }
}

Using Authentication with Google Provider

The ".write" works perfectly, however the ".read" no (perm error), I already changed it to:

".read": true //Leitura pública

But it didn’t work either, I believe the error lies in the structure of my rule but I don’t know where

To "work," I changed the rules to:

{
  "rules": {
    "receita": {
      "$chave": { 
        ".write": "auth.uid === newData.child('usuario').val()"
      },
      ".read": "true"
    }
  }
}

I tested so too, but unsuccessfully:

".read": "auth.uid === data.child($chave + '/usuario').val() || data.child($chave + '/tipo').val() === true"

With the rules structured in the first way, I tried to fetch the data as follows:

firebase.database().ref('receita').once('value').then(function(snapshot) {
    console.log(snapshot.val())
})

However it results in the permission error, but when doing so passing a valid key to reference works:

firebase.database().ref('receita/-L8UX8Ajz8P1XcudJUih').once('value').then(function(snapshot) {
    console.log(snapshot.val())
})

So the error is picking up a reference from the bank because in the recipe directory (/receita), I have no rule, only in /receita/$chave

  • You have the rule auth.uid === newData.child('usuario').val(), but in your bank, I see you have the user -L7WxcAHr8LkfJAiI8ku. This id seems to have been generated by a push() in the database. The auth.uid has a different value than this push. So the rule will always return false.

  • @Rosáriopereirafernandes no, the value -L7WxcAHr8LkfJAiI8ku is generated by Authentication, use push only to add a recipe object key. the method that defines the user key: auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()).then(function(result) { chave_usuario = result.user.uid; })

  • Very well... but what you’re trying to do seems contradictory. Its rules allow reading only recipes created by a user and true type (there is a filtering). But you want the rules to allow you to read all recipes (no filtering).. Are you trying to do queries for 2 types of user? The "admin" reads all recipes and the normal user reads only his recipes?

  • 1

    The idea is: Users can see their revenues (public or private); Users can see public revenues (tipo === true); I have no admin or normal user, only users

  • 1

    Is not "Its rules allow reading only recipes created by a user and of the true type", and yes "Its rules allow reading only recipes created by the connected user OR true-type"

2 answers

4

So the error is taking a reference from the database because in the directory recipe (/recipe), I have no rule, only on /recipe/key

That is absolutely correct!

To solve this problem, you can use the query-based Rules.

For the user to see all your recipes (public or private), you would query:

firebase.database().ref('receita').orderByChild('usuario').equalTo(currentUser.uid)
.once('value').then(function(snapshot) {
    console.log(snapshot.val())
})

For the user to see only public revenues:

firebase.database().ref('receita').orderByChild('tipo').equalTo(true)
.once('value').then(function(snapshot) {
    console.log(snapshot.val())
})

Then just indicate in the rules that only these 2 queries are allowed:

{
    "rules":{
        "receita":{
            ".read":"(query.orderByChild == 'usuario' && query.equalTo == auth.uid) || (query.orderByChild == 'tipo' && query.equalTo == true)",
            "$chave":{
                ".write":"auth.uid === newData.child('usuario').val()"
            }
        }
    }
}
  • But doing so would lose the sort by recipe name, how to solve?

  • Also try adding the rule ". indexOn":"name"

  • Maybe (with a little Gambi) I can do it this way, but it would complicate a lot since I have other query that would make it very difficult. What I really want is to know why my rules don’t work

0


I was able to solve the problem by changing the structure of the bank, dividing the data access information and the data itself

Bank structure:

{
  "receita" : {
    "acesso" : {
      "-L92JgTg4xIDCymtq26h" : {
        "tipo" : true,
        "usuario" : "Az2Mra1xJwXtpaspGwgvj7hm9NA2"
      },
      "-L9CwBmuVETG5TSjLHz7" : {
        "tipo" : true,
        "usuario" : "Az2Mra1xJwXtpaspGwgvj7hm9NA2"
      }
    }
    "dados" : {
      "-L92JgTg4xIDCymtq26h" : {
        "imagem" : "default",
        "ingrediente" : [ "teste" ],
        "nome" : "teste",
        "preparo" : "teste"
      },
      "-L9CwBmuVETG5TSjLHz7" : {
        "imagem" : "default",
        "ingrediente" : [ "teste" ],
        "nome" : "teste",
        "preparo" : "teste"
      }
    }
  }
}

Bank rules:

{
  "rules": {
    "receita": {
      "acesso": {
        ".read": true,
        "$chave": {
          ".write": "data.exists() && auth.uid === data.child('usuario').val() || !data.exists() && auth.uid === newData.child('usuario').val()"
        },
        ".indexOn": ["usuario", "tipo"]
      },
      "dado": {
        "$chave": {
          ".write": "auth.uid === root.child('receita/acesso/' + $chave + '/usuario').val()",
          ".read": "auth.uid === root.child('receita/acesso/' + $chave + '/usuario').val() || root.child('receita/acesso/' + $chave + '/tipo').val() === true",
          ".indexOn": "nome"
        }
      }
    }
  }
}

Thus, the access data are public, but to see the revenue data is necessary the permission

Browser other questions tagged

You are not signed in. Login or sign up in order to post.