在这种情况下编写Firebase规则的最佳实践是什么? [英] What is the best practice to write the rules of Firebase in a situation like this?

查看:119
本文介绍了在这种情况下编写Firebase规则的最佳实践是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

用户将能够写入自己的 user 节点.然后,用户必须能够编写他/她想要的许多建筑物和他/她想要的许多部门(还有房间 >,但为了清楚起见,我暂时将其放在一边).用户应该能够读取(和写入)自己的用户节点,建筑物和部门,但不能读取(和写入)其他用户的节点,建筑物和部门.

The user will be able to write to his own user node. Then the user has to be able to write as many buildings he/she wants and as many depts as he/she wants (there are also rooms but I will leave that aside for now for clarity's sake). The user should be able to read (and write) his own user node, buildings and departments but not the other users' node, buildings and departments.

基本上:

用户>用户的建筑物>建筑物的部门(共有读写权限)

User > user's Building > building's Department (TOTAL read and write permissions)

用户>另一个用户的资料(完全没有权限)

User > Another User's Stuff (NO Permissions at all)

这是数据库结构:

{
  "buildings" : {
    "-L9Bc9aazn3mNiW1elJk" : {
      "address" : "",
      "comments" : "",
      "hasDepts" : {
        "-L9FwBmYEnkZQzdFJ4lU" : true
      },
      "name" : "J house",
      "ownerID" : "6hwNde08Wuaa9bfReR28niSbOsF3"
    }
  },
  "depts" : {
    "-L9FwBmYEnkZQzdFJ4lU" : {
      "comments" : "",
      "inBuilding" : "-L9Bc9aazn3mNiW1elJk",
      "name" : "Dep 1"
    },
  },
  "users" : {
    "6hwNde08Wuaa9bfReR28niSbOsF3" : {
      "isAdmin" : {
        "-L9Bc9aazn3mNiW1elJk" : true,
      }
    }
  }

初始方法

每个用户节点都有一个子节点 isAdmin ,其中包含该用户创建的建筑物的所有按键.使用相同的逻辑,建筑物节点包含一个 hasDepts 节点,其中包含用户在该建筑物中创建的所有 depts 按键

Initial approach

Each users node has a child node isAdmin that contains all push keys of the buildings this user has created. Using the same logic, the buildings' node contains a hasDepts node with all the push keys from the depts that the user has created in that building.

如果您能提供帮助,我将不胜感激.外面有人吗?

If you can help I would really appreciate. Anybody out there?

我正在使用vue.js这样写到Firebase:

I am using vue.js to write to firebase like this:

addBuilding: function () {
  let userId = firebase.auth().currentUser.uid;
  let buildingKey = buildingsRef.push().key;
  this.newBuilding.ownerID = userId;
  buildingsRef.child(buildingKey).set(this.newBuilding);
  usersRef.child(userId).child('isAdmin').child(buildingKey).set(true);
}

到目前为止,最近的解决方案/@AndréKool(部分使用初始方法)

"users": {
  "$uid": {
    ".read": "$uid === auth.uid",
    ".write": "$uid === auth.uid"
  },
}, 
"buildings": {
    "$pushKey" : {
        ".read": "root.child('buildings').child($pushKey).child('ownerID').val() === auth.uid",
        ".write": "!data.exists() || root.child('buildings').child($pushKey).child('ownerID').val() === auth.uid" 
  }
},
"depts": {
  "$pushKey": {
    ".read": "root.child('buildings').child(root.child('depts').child($pushKey).child('inBuilding').val()).child('ownerID').val() === auth.uid",
        ".write": "root.child('buildings').child(root.child('depts').child($pushKey).child('inBuilding').val()).child('ownerID').val() === auth.uid" 

  }
},

}

通过@AndréKool的尝试,模拟器使它可以读取/写入 buildings/$ pushKey 节点.但是,虽然它在创建节点后立即在前端显示该节点,但是当我们刷新浏览器或添加新建筑物时,该节点将从前端消失(仍保留在数据库中). Firebase也不允许写入 depts 节点.有任何线索和可能的解决方案吗?

With @André Kool's attempt the simulator allows it to read/write to the buildings/$pushKey node. However while it shows the node on the frontend as soon as it it is created, when we refresh the browser or add a new building the node disappears from the frontend (remains on the database). Firebase it's also not allowing to write to the depts node. Any clues and possible solutions?

1)确保建筑物部门节点都具有 ownerId 子节点,如下所示:

1) making sure both the buildings and depts nodes both have the ownerId child node, like this:

{
  "buildings" : {
    "-L9HIbKu5fIe8rfoePgi" : {
      "address" : "",
      "comments" : "",
      "hasDepts" : {
        "-L9HIdScisDItysCnMlm" : true
      },
      "name" : "building 1",
      "ownerID" : "6hwNde08Wuaa9bfReR28niSbOsF3"
    }
  },
  "depts" : {
    "-L9HIdScisDItysCnMlm" : {
      "comments" : "",
      "inBuilding" : "-L9HIbKu5fIe8rfoePgi",
      "name" : "dep 1",
      "ownerID" : "6hwNde08Wuaa9bfReR28niSbOsF3"
    }
  },
  "users" : {
    "6hwNde08Wuaa9bfReR28niSbOsF3" : {
      "isAdmin" : {
        "-L9HIbKu5fIe8rfoePgi" : true
      },
      "name" : "João Alves Marrucho",
      "userEmail" : "joaomarrucho@hotmail.com"
    }
  }
}

2)使用 ownerId 授权对所有建筑物和部门的读写:

2) Use the ownerId to authorise read and writing on all buildings and depts:

"users": {
      "$uid": {
        ".read": "$uid === auth.uid",
        ".write": "$uid === auth.uid"
      },
    }, 
    "buildings": {
      "$id": {
        ".read": "data.child('ownerID').val() == auth.uid" , 
        ".write": "data.child('ownerID').val() == auth.uid"  
      }
    },
    "depts": {
      "$id": {
        ".read": "data.child('ownerID').val() == auth.uid" , 
        ".write": "data.child('ownerID').val() == auth.uid"  
      }
    },
  }

3)这种方法带来了新问题!

3) New problem with this approach!

根据上述规则,使用模拟器,在我看来,firebase不允许用户读取/写入建筑物节点,但允许读取/写入建筑物/$ pushKey 节点. firebase是否需要用户能够读写父节点( buildings )和子节点( buildings/$ pushKey )?如果是这样,如何防止用户删除(.set)整个建筑物节点?

With the rules above, using the simulator, it seems to me like firebase is not allowing the user to read/write to the buildings node but it's allowing to read/write to buildings/$pushKey node. Does firebase needs the user to be able read/write to both parent (buildings) and child node (buildings/$pushKey)?. And if so how can you prevent the user from deleting (.set) the whole buildings node?

我之所以这样问是因为,如果我们在 $ wildcards 之前添加.read":true,".write":true ,它将写出预期的数据库结构而使级联上的下一个规则完全无用 ...所以这不好,但至少可以暗示解决方案的一部分可能存在.

I am asking this because if we add ".read": true, ".write": true before the $wildcards it writes the intended database structure while rendering the next rules on the cascade completely useless... So that's no good, but at least it kind of hints where part of the solution may reside.

 "users": {
      ".read": true, <<<<<<
      ".write": true,   <<<<<<
      "$uid": {
        ".read": "$uid === auth.uid",
        ".write": "$uid === auth.uid"
      },
    }, // but is should also be able to write to his own buildings
    "buildings": {
      ".read": true,   <<<<<<
      ".write": true,   <<<<<<
      "$id": {
        ".read": "data.child('ownerID').val() == auth.uid" , 
        ".write": "data.child('ownerID').val() == auth.uid"  
      }
    },
    "depts": {
      ".read": true,   <<<<<<
      ".write": true,   <<<<<<
      "$id": {
        ".read": "data.child('ownerID').val() == auth.uid" , 
        ".write": "data.child('ownerID').val() == auth.uid"  
      }
    },
  }

(其他想法) 我不明白为什么用户不应该能够读取/写入建筑物父节点(只要规则阻止他删除整个建筑物节点,并且只能删除授予他对他创建的建筑物/$ pushKeys 的完全访问权限).那复杂吗?我可能会错了,但是firebase不需要先扫描建筑物节点,然后知道属于用户的那个节点?
如果Firebase规则无法像这样解决此问题,则意味着从理论上讲,用户需要在其中将其自己的内容读写到实时数据库中的每个Firebase应用程序(通常是这种情况)都需要将信息存储在 users.uid 节点以使其可供他/她使用.这似乎违背了使数据库保持尽可能平坦"的firebase通用说明,并且它与在firebase中具有子级的数据库引用的任何函数都需要data.snapshots噩梦般的迭代这一事实并不一致. 此外,如果您无法设计出浅层结构,并且用户ID会不断变化,那么您将如何在Apps Firebase配置中编写数据库引用: const buildingRef = db.ref('users/'+ userId !!!! +'/buildings'); :>

(Other thoughts) I don't see why the user shouldn't be able to read/write to the buildings parent node (provided the rules prevent him from deleting the whole buildings node and only grant him full access to the buildings/$pushKeys he creates). Is that complicated? I may be getting this wrong, but doesn't firebase need to scan the buildings node before it knows which one belongs to the user?
If firebase rules can't resolve this issue like this, that means that in theory, every firebase app in which the user needs to read and write its own content to the realtime database, which is often the case, needs to store the information under a users.uid node to make it available to him/her. That seems to go against the "keep your database as flat as possible" firebase general instruction, and it also doesn't play well with the fact that any function with database references that have children in firebase require that data.snapshots nightmarish iteration. Moreover if you can't design a shallow structure, and the user id will constantly change, how would you go about writing the database references in the Apps firebase configuration: const buildingsRef = db.ref('users/'+ userId!!!!+'/buildings'); : >How to constrain read/write rules to the users that create the nodes while keeping this structure? There must be an good way to do this without bending over backwards. ?

推荐答案

以下是数据结构各部分的规则:

Here are the rules for each part of your datastructure:

对于用户节点,我删除了更全局的读取和写入规则,因为如果它们为假,则它们是多余的,因为这是默认状态.如果它们是真的,它们将覆盖这些规则,因为规则级联.要允许用户仅读/写他们自己的数据,请执行以下操作:

For the users node I removed the more global read and write rules because if they are false they are redundant because that is the default state. And if they are true they will override these rules because rules cascade. To allow users to only read/write their own data:

"users": {
  "$uid": {
    ".read": "$uid === auth.uid",
    ".write": "$uid === auth.uid"
  }
}

接下来是建筑物节点.在这里,您可以查看自己是否是所有者(ownerID ===您的uid),并可以写出

Next is the buildings node. Here you can read if you are the owner (ownerID === your uid) and write if there is no data or you are the owner:

"buildings" : {
    "$pushKey" : {
        ".read": "root.child('buildings').child($pushKey).child('ownerID').val() === auth.uid",
        ".write": "!data.exists() || root.child('buildings').child($pushKey).child('ownerID').val() === auth.uid"
    }
}

最后是部门节点,因为用户只能在自己拥有的建筑物中读取/写入部门,因此它有点棘手.因此,我们必须使用部门的按键来检查用户是否有建筑物.在这里,我检查部门中具有inBuilding值的建筑物是否具有所有者ID(即您的uid)(您的想法很复杂):

And last is the departments node where it gets a little tricky because a user can should only read/write departments in buildings he owns. So we have to check if the user has a building with the pushkey of the department. Here I check if the building with the value of inBuilding in the department has ownerID that is your uid (mind spinning complicated):

"depts" : {
    "$pushKey" : {
        ".read": "root.child('buildings').child(root.child('depts').child($pushKey).child('inBuilding').val()).child('ownerID').val() === auth.uid",
        ".write": "root.child('buildings').child(root.child('depts').child($pushKey).child('inBuilding').val()).child('ownerID').val() === auth.uid"
    }
}

另一种选择是将您的数据结构更改为类似的形式,您可以在该建筑物中以用户ID存储建筑物和部门:

Another option is changing your datastructure to something like this where you store buildings and departments under the user id:

{
    "buildings" : {
        "$uid" : {
            ".read": "$uid === auth.uid",
            ".write": "$uid === auth.uid",
            "$buildingid" : {    
            }
        }
    },
    "depts" : {
        "$uid" : {
            ".read": "$uid === auth.uid",
            ".write": "$uid === auth.uid",
            "$deptid" : {    
            }
        }
    }
}

这篇关于在这种情况下编写Firebase规则的最佳实践是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆