【问题标题】:Firebase Database Rules for groups群组的 Firebase 数据库规则
【发布时间】:2017-11-28 14:14:08
【问题描述】:

我有这个 Firebase 数据库,如有必要可以更改:

该数据库的 JSON 是:

{
  "groups": {
    "1": {
      "name": "G1",

      "points": {
        "1": {
            "name": "p1"
        }
      },
      "visits": {
        "1": {
            "name": "v1"
        }
      },
      "areas": {
        "1": {
            "name": "a1"
        }
      },
      "waypoints": {
        "1": {
            "name": "w1"
        }
      },
      "interests": {
        "1": {
            "name": "i1"
        }
      }
    },
    "2": {
      "name": "G2",

      "points": {
        "2": {
            "name": "p2"
        }
      },
      "visits": {
        "2": {
            "name": "v2"
        }
      },
      "areas": {
        "2": {
            "name": "a2"
        }
      },
      "waypoints": {
        "2": {
            "name": "w2"
        }
      },
      "interests": {
        "2": {
            "name": "i2"
        }
      }
    }
  },
  "users": {
    "qdRw1khg1ZO1s52YioYCdM4WrD02": {
      "firstName": "AAAA",
      "lastName": "BBB",
      "email": "sdf@sdfs.com"     
    },
    "h3KYDXkPQrY246w6Y6NXIanVoNS2": {
      "firstName": "FF",
      "lastName": "RR",
      "email": "wwf@jjuzhz.com"
    }
  },
  "userGroups": {
    "qdRw1khg1ZO1s52YioYCdM4WrD02": {
      "1": "admin",
      "2": "readwrite"
    },
    "h3KYDXkPQrY246w6Y6NXIanVoNS2": {
      "1": "admin",
      "2": "readonly"     
    }
  }
}

我想定义规则来完成以下任务:

  • 每个人都可以创建一个新组
  • 只有群组的用户才能读取群组数据
  • 只有组的“管理员”可以将数据写入组本身,添加用户和更改组数据的子级别,但
    • “readwrite”组用户可以写入子级别“points”和“visits”
    • “只读”组用户根本不能写

我有:

"groups": {          
  "$groupId": {
    ".read": "root.child('userGroups').child(auth.uid).child($groupId).exists()",
    ".write": "! root.child('userGroups').child(auth.uid).child($groupId).exists() || 
                          (data.parent().val() === 'points' && root.child('userGroups').child(auth.uid).child($groupId).val() != 'readonly') ||
                        (data.parent().val() === 'visits' && root.child('userGroups').child(auth.uid).child($groupId).val() === 'readonly') ||
                        (data.parent().val() != 'points' && data.parent().val() != 'visits' && root.child('userGroups').child(auth.uid).child($groupId).val() === 'admin')"
  }
},
"users": {
  "$userId": {
    ".read": "auth != null",
    ".write": "auth != null && 
              $userId === auth.uid && 
              newData.val() != null"
  }
},
"userGroups": {
  "$userId": {
    ".read": "auth != null",
    ".write": "auth != null && 
               data.child(auth.uid).val() === 'admin' && 
               newData.val() != null"          
  }
}

但这不起作用,因为

data.parent().val()

不返回父级的名称字符串。所以我做不到

data.parent().val() != 'points'

如何解决这个问题?问题是根据指定的规则将数据写入组。

【问题讨论】:

  • 什么具体的要求给了问题?该要求被编码成什么规则?您是否有无法读取/写入的代码示例?此外,您能否将屏幕截图替换为实际的 JSON,以便我可以使用您的数据进行测试。您可以通过单击 Firebase Database console 中的“导出 JSON”链接来获取此信息。
  • 一旦您授予用户访问某个级别的数据的权限,您就不能在较低级别取消该权限。这也是 Firebase 文档建议扁平化数据结构的原因之一。在您的场景中,我会将pointsvisits 分离到一个单独的顶级节点中。
  • 最好按照您的建议将数据展平。
  • 是的,在您当前的结构中,集团层面的运营总是充满挑战。但是我正在尝试是否可以在儿童级别上使其安全。我将在答案中发布更新,因为它们在 cmets 中不可读。

标签: json firebase firebase-realtime-database firebase-security


【解决方案1】:

如果您尝试“点”和“访问”级别的嵌套规则会怎样:

"groups": {          
  "$groupId": {
    ".read": "root.child('userGroups').child(auth.uid).child($groupId).exists()",
    ".write": "root.child('userGroups').child(auth.uid).child($groupId).val() == 'admin'",
    "points": {
      ".write": "root.child('userGroups').child(auth.uid).child($groupId).val() != 'readonly'"
    },
    "visits": {
      ".write": "root.child('userGroups').child(auth.uid).child($groupId).val() != 'readonly'"
    }
  }
},
"users": {
  "$userId": {
    ".read": "auth != null",
    ".write": "auth != null && 
              $userId === auth.uid && 
              newData.val() != null"
  }
},
"userGroups": {
  "$userId": {
    ".read": "auth != null",
    ".write": "auth != null && 
               data.child(auth.uid).val() === 'admin' && 
               newData.val() != null"          
  }
}

【讨论】:

  • 我也这么认为,但是当我在 Firebase 规则模拟器中运行它时,看起来嵌套规则被忽略并且不会被考虑。
  • 你能贴一张模拟器的截图给你错误的结果吗?通过多个测试对我来说效果很好:imgur.com/IEta3zX imgur.com/e1B76i5
  • 也看上面@Frank的评论。
  • 检查我上次的编辑,“$groupId”中的“.write”应该有“!”删除,而不是 .exists() 最后尝试 .val() == 'admin'
  • 但是我无法创建新组,因为我需要在创建时没有的 userGroups 中的管理员条目。
【解决方案2】:

Firebaser 在这里。预计这个答案会随着我的进展而更新。

我的第一步是将特定子节点的规则移动到该特定子节点中。这消除了您一直遇到的parent() 问题。第一次迭代是:

  "groups": {          
    "$groupId": {
      ".read": "root.child('userGroups').child(auth.uid).child($groupId).exists()",
      "points": {
        ".write": "root.child('userGroups').child(auth.uid).child($groupId).val() !== 'readonly'"
      }
    }
  },

这允许用户h3KYDXkPQrY246w6Y6NXIanVoNS2 写入/groups/1/points(用户是管理员),但不能写入/groups/2/points(用户只有只读访问权限)。

下一步是使规则更通用。为此,我引入了一个 $child 变量,它匹配组下的任何节点:

  "groups": {          
    "$groupId": {
      ".read": "root.child('userGroups').child(auth.uid).child($groupId).exists()",
      "$child": {
        ".write": "root.child('userGroups').child(auth.uid).child($groupId).val() !== 'readonly'
                   || ($child !== 'points' && $child !== 'visits')"
      }
    }

这允许用户h3KYDXkPQrY246w6Y6NXIanVoNS2 写入/groups/2/name(任何组成员均可写入),但不能写入/groups/2/points(用户只有只读访问权限)。

更新:显然我颠倒了你上面的逻辑,所以这是我最后的看法:

  "groups": {          
    "$groupId": {
      ".read": "root.child('userGroups').child(auth.uid).child($groupId).exists()",
      ".write": "root.child('userGroups').child(auth.uid).child($groupId).val() == 'admin'",
      "$child": {
        ".write": "root.child('userGroups').child(auth.uid).child($groupId).val() === 'readwrite'
                   && ($child !== 'points' || $child !== 'visits')"
      }
    }

与此用户h3KYDXkPQrY246w6Y6NXIanVoNS2:

  • 可以写信给/groups/1/name,因为他们是第 1 组的管理员
  • 可以写信给/groups/2/points,因为他们是第 1 组的管理员
  • 不能写信给/groups/2/name,因为他们不是第 2 组的管理员
  • 可以写信给/groups/2/points,因为他们是第 2 组的读写成员

【讨论】:

  • @juergen_d:除了管理员要求(Pat 的回答简洁明了),我上次的 sn-p 还缺少什么?
  • 现在除了积分和访问之外,所有用户都可以写入群组。但只有管理员才能做到这一点。我会尝试解决这个问题。
  • 在 $child ".write" 条件中,将其更改为 "root.child('userGroups').child(auth.uid).child($groupId).val() === 'admin' || (root.child('userGroups').child(auth.uid).child($groupId).val‌​() === 'readwrite' && ($child === 'points' || $child === 'visits') )"
  • 啊,我想我把你的逻辑倒过来了。
  • 查看我的最新版本。它比您的更简洁,因为它捕获了更高级别的管理员(就像 Pat 在他的回答中所做的那样)。我实际上认为最终规则是非常易读的,所以你也许可以坚持使用当前的数据模型。除非读取权限也因组成员级别而异,否则在这种情况下,扁平化几乎总是可行的方法。
猜你喜欢
  • 1970-01-01
  • 2017-07-15
  • 2019-05-28
  • 2020-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-24
相关资源
最近更新 更多