In Firebase Realtime Database Rules, how do you give write access to the users with a certain child value?

ぃ、小莉子 提交于 2021-02-20 00:49:10

问题


,"people" : {
  ".read": "auth != null",
  "$uid":  {
  },
  "e2" : {     
    ".read": "auth.uid != null",
    ".write": "$uid == auth.uid"  
  },
  "l1" : {     
    ".read": "auth.uid != null",
    ".write": "auth.uid != null"  
  }

So e2 is the @ of an email. For example @gmail or @aol or @yahoo. For the l1 child, I want to make the write rule: Write if auth.uid != null && e2 has the same value as the e2 of the person you are writing l1 to. The furthest I could get, is something like this:

"data.parent().child(people).hasChildren(['auth.uid', 'l1'])"    

JSON

"people": {
    "02PdiNpmW3MMyJt3qPuRyTpHLaw2": {
        "e2": "aol.com",
        "l1": 4,
        "X": {
            "e2": "aol.com",
            "l1": 0,
            "P": {
                "e2": "gmail.com",
                "l1": 0,

Basically l1 = like, so a user writes to another users's l1 in the form of adding 1 more to the count.

Operation that should succeed:

A user X wants to like the user with uid 02PdiNpmW3MMyJt3qPuRyTpHLaw2. User X has a e2 child of @aol.com. This is the same as the e2 child of the user he wants to like. User x is also an authorized user, therefore he meets the 2 requirements to write to the l1 of the user he wants to like.

Operation that should not succeed:

User P wants to like the user with uid 02PdiNpmW3MMyJt3qPuRyTpHLaw2. User P has a e2 child of @gmail.com. This is not the same as the e2 child of the user he wants to like. User P therefore does not meet the requirement to write to the l1 of the user he wants to like


回答1:


This is a really involved scenario, so I'm going to walk through it step-by-step. There is a good chance you'll need to make changes to make these rules work for your complete use-case, so I'm hoping that having each step will make it possible for you to tune them yourself.


The first step is to deobfuscate your data structure. I'll instead use this structure to get started:

{
  "people" : {
    "user1" : {
      "domain" : "aol.com",
      "likeCount" : 2,
      "likers" : {
        "user2" : {
          "comain" : "aol.com"
        },
        "user3" : {
          "domain" : "aol.com"
        }
      }
    }
  }
}

So user1 has two likes, by user2 and user3 both from the same domain.

I highly recommend using meaningful names like this in your database in general, but definitely in questions that you post about it. If people can't easily understand your data model, chances of them helping go down rapidly.


In the above data model, we can ensure that only users from the same domain can like this user with:

  "people": {
    "$uid": {
      "likers": {
        "$likerid": {
          ".write": "data.parent().parent().child('domain').val() == newData.child('domain').val()"
        }
      }
    }
  }

With these rules, I've tried two write operations to people/user1/likers/user4. The first operation succeeds:

{
  "domain": "aol.com"
}

The second operation fails:

{
  "domain": "gmail.com"
}

We should probably also ensure that a user can only write their own likes, and not for other users. We can do that with:

  "people": {
    "$uid": {
      "likers": {
        "$likerid": {
          ".write": "$likerid == auth.uid && 
            data.parent().parent().child('domain').val() == newData.child('domain').val()"
        }
      }
    }
  }

Next up, we'll add a rule that allows a user to like someone, only if they haven't liked them before. We'll do that on people/$uid as we'll need to look at data under likers and under likesCount soon.

The rules for the first step are:

  "people": {
    "$uid": {
      ".write": "
        !data.child('likers').child(auth.uid).exists() && newData.child('likers').child(auth.uid).exists()
      ",
      "likers": {
        "$likerid": {
          ".write": "$likerid == auth.uid && 
            data.parent().parent().child('domain').val() == newData.child('domain').val()"
        }
      }
    }

So these rules allow us to write to a user, if we are adding a like that doesn't exist yet. You may need to do additional checks here to allow updates of other child nodes, but for here we'll keep things as simple as possible (as it's already pretty involved).


Finally you want to ensure that the write must also increment the likeCount, which should be something like this:

  "people": {
    "$uid": {
      ".write": "
        !data.child('likers').child(auth.uid).exists() && newData.child('likers').child(auth.uid).exists()
        && newData.child('likeCount').val() == data.child('likeCount').val() + 1
      ",
      "likers": {
        "$likerid": {
          ".write": "$likerid == auth.uid && 
            data.parent().parent().child('domain').val() == newData.child('domain').val()"
        }
      }
    }

So the new line now checks if thew new data at likeCount is one higher than its previous value.


I've taken each of the steps above in a test database of my own, and tested in the playground with both positive and negative cases. So while there may be some issues, the basic approach of each step works.

As said this is pretty involved, and it's quite likely that you'll need to make significant changes before it fully works for all your use-cases.



来源:https://stackoverflow.com/questions/63441847/in-firebase-realtime-database-rules-how-do-you-give-write-access-to-the-users-w

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!