当observeSingleEvent时Swift Firebase规则权限被拒绝

Posted

技术标签:

【中文标题】当observeSingleEvent时Swift Firebase规则权限被拒绝【英文标题】:Swift Firebase Rule Permissions Denied when observeSingleEvent 【发布时间】:2018-08-09 11:22:58 【问题描述】:

我正在开发一个应用程序,让教师可以记录学生的课程。使用 Firebase 规则我想允许教师访问某些学校。我有以下规则:


  "rules": 
    "Schools" : 
      "$schoolId" : 
          ".read" : "data.child('Teachers').hasChild(auth.uid)",
         ".write" : "data.child('Teachers').hasChild(auth.uid) ||
          root.child('User').child(auth.uid).child('Invitation').exists()"
      
    ,
    "Users" : 
      "$uid" : 
        ".read" : "auth.uid === $uid",
            ".write": "auth.uid === $uid"
      
    
  

在模拟器中一切正常,但是当触发以下所有权限时,所有学校都被拒绝。

DataService.ds.REF_SCHOOLS.observeSingleEvent(of: .value)  (snapshot) in
    MySchools.mySchoolKeyList.removeAll()
    MySchools.mySchoolList.removeAll()
    if let snapshot = snapshot.children.allObjects as? [DataSnapshot] 
        for snap in snapshot 
            if let recordDict = snap.value as? Dictionary<String, AnyObject> 
                if let name = (recordDict["SchoolName"] as? String) 
                    MySchools.mySchoolList.append(name)
                
                MySchools.mySchoolKeyList.append(snap.key)
            
        
            if MySchools.mySchoolList.isEmpty 
                MySchools.mySchoolList.append("You do not belong to any schools.")
            
    

以下是 Firebase 数据库的快照供参考:

有人知道我的规则有什么问题吗?也将不胜感激如何处理权限被拒绝的结果。

【问题讨论】:

DataService.ds.REF_SCHOOLS 指向Schools 还是School/Some_school_ID 指向 Database.database().reference().child("Schools") 【参考方案1】:

您的代码正在尝试从/Schools 读取,但您的规则未授予任何人从/Schools 读取的权限。所以 Firebase 正确地拒绝了读取。

我感觉您希望读取操作自动过滤结果以仅返回用户有权访问的学校节点 (/Schools/$schoolId)。但这不是 Firebase 安全规则的工作方式:rules cannot be used to filter data。

对于开始使用 Firebase 的服务器端安全规则的开发人员来说,这是一个常见的混淆来源,因此我建议您查看之前的一些 questions mentioning "rules are not filters"。


现在一种获取过滤数据的方法,无需让用户访问所有Schools。为此,您需要:

    使用查询仅请求您应该有权访问的学校。 验证您的安全规则中的 /Schools 是否允许此查询。

有关此示例,请参阅文档中的 query based rules。

代码应该是这样的:

let query = DataService.ds.REF_SCHOOLS.queryOrdered(byChild: "Teachers/"+uid).queryValue(equalTo: true);
query.observeSingleEvent(of: .value)  (snapshot) in
  ...

但是这样做的问题是您需要为每个教师定义一个索引。虽然这在技术上是可行的,但会导致索引数量不合理。


事后看来:您当前的数据结构可让您有效地找到特定学校的教师。但是,它不允许您有效地为特定教师找到学校。

要有效地为特定教师查找学校,请在数据库中添加一个额外的数据结构,将学校映射到每位教师。例如

teacherSchools
  teacherUid1
    schoolId1: true
    schoolId2: true
  teacherUid2
    schoolId2: true
    schoolId3: true

使用这种结构,您可以轻松读取教师的所有学校 ID,然后加载每所学校。由于Firebase pipelines the requests over a single connection,此加载速度比大多数开发人员预期的要快得多。

有关此方法的更长/另一种解释,请参阅Firebase query if child of child contains a value 和Firebase Query Double Nested。

【讨论】:

以上是关于当observeSingleEvent时Swift Firebase规则权限被拒绝的主要内容,如果未能解决你的问题,请参考以下文章

第一次调用时捕获 Firebase 实时observeSingleEvent 数据失败

Firebase:如何在observeSingleEvent() 之后删除Observer(withHandle:)?

试图从 firebase Swift 获取数据

Swift -Firebase 可以同时发布和观察

变量的值在observeSingleEvent 中没有变化

斯威夫特火力.observe或.observeSingleEvent将无法正常工作