Javascript Firebase数据库规则-仅允许未经身份验证的用户进行筛选查询

Javascript Firebase数据库规则-仅允许未经身份验证的用户进行筛选查询,javascript,firebase,firebase-realtime-database,firebase-security,Javascript,Firebase,Firebase Realtime Database,Firebase Security,我有一个Google Firestore实时数据库,其中包含一个标志isPublic。如果设置为true,则未经身份验证的用户可以读取子节点详细信息。如果设置为false,则记录只能由一个(目前)经过身份验证和授权的用户访问 授权用户是唯一具有写入权限的用户 此外,子节点private始终仅向一个授权用户授予访问权限 我研究的解决方案基于基于查询的规则 不幸的是,我得到了一个权限\u拒绝响应,即使是作为授权用户 旁白:这是一个使用Firebase SDK的Vue JS项目 这是我的数据库示例 对

我有一个Google Firestore实时数据库,其中包含一个标志
isPublic
。如果设置为
true
,则未经身份验证的用户可以读取子节点
详细信息。如果设置为
false
,则记录只能由一个(目前)经过身份验证和授权的用户访问

授权用户是唯一具有写入权限的用户

此外,子节点
private
始终仅向一个授权用户授予访问权限

我研究的解决方案基于基于查询的规则 不幸的是,我得到了一个
权限\u拒绝
响应,即使是作为授权用户

旁白:这是一个使用Firebase SDK的Vue JS项目

这是我的数据库示例

对于未经身份验证的用户,第一个产品应具有对
详细信息
的读取权限,但不应具有对
私人
的读取权限

通过强制未经身份验证的用户运行查询
dbRef.orderByChild('isPublic').equalTo(true)

还有我的工作规则

"rules": {
  "products": {
    "$product_id": {
      ".indexOn": "isPublic",
      ".read": "query.equalTo == true || auth.uid == '[admin user id]'"
      // alternative attempt
      // ".read": "(query.orderByChild == 'isPublic' && query.equalTo == true) || auth.uid == '[admin user id]'",
      ,
      ".write": "auth.uid == '[admin user id]'",

      "details": {
        ".read": true,
      },
      "private": {
        ".read": "auth.uid == '[admin user id]'",
      }
    }
  }
}
对于未经授权的用户,此查询应授予对“详细信息”子节点的读取权限:

firebase.database().ref('products').orderByChild('isPublic').equalTo(true).once('value'))
.然后(…)
此查询仅针对授权用户,应授予对所有数据的读取权限

firebase.database().ref('products')。once('value'))
.然后(…)

使用当前设置,无论是否以授权用户身份登录,我都会收到任何查询的“权限被拒绝”。

如果希望用户能够从
产品
节点进行读取,则需要在该节点上设置
.read
规则。由于您只希望在公共产品查询时允许读取,因此应该验证该特定查询

大概是这样的:

“规则”:{
“产品”:{
“.indexOn”:“isPublic”,
“.read”:”(query.orderBy='isPublic'&&query.equalTo==true)
||auth.uid=='[管理员用户id]'”
}
}
因此:

  • 您将规则定义的级别太低,这意味着对
    /products
    的所有读取都被拒绝
  • 您的规则没有检查
    orderBy
    字段

  • 请注意,您在
    private
    上声明的附加
    .read
    规则在这里毫无意义,因为同一用户已经在整个“产品”节点上获得了读取权限。

    Franks的回答为我指明了正确的方向(谢谢!),但我决定自己发布一个更完整的回答

    这是数据结构。请注意,我将“isPublic”更改为“isPublished”。 “products”现在包含两个子节点:“private”和“public”。两者使用相同的键

    // Firebase Data
    "products": {
      "private" : {
        "-pushId_1" : {
          "notes" : "Private notes product 1",
          "soldDate" : ""
        },
        "-pushId_2" : {
          "notes" : "Private notes product 2",
          "soldDate" : ""
        }
    
      },
      "public" : {
        "-pushId_1" : {
          "imageURL" : "https://firebasestorage.imagexyz",
          "isPublished" : true,
          "title" : "Published product title",
        },
        "-pushId_2" : {
          "imageURL" : "https://firebasestorage.imagexyz",
          "isPublished" : false,
          "title" : "Unpublished product title, only accessible if authorized",
        }
      }
    }
    
    如果查询查找已发布的产品,则这些规则允许管理员执行所有操作,并允许未经身份验证的访问公共子节点

    // Firebase Rules
    {
      "rules": {
        "products" : {
          ".read": "auth.uid == '[admin user id]'",
          ".write": "auth.uid == '[admin user id]'",
    
          "public" : {
            ".indexOn": "isPublished",
            ".read": "(query.orderByChild == 'isPublished' && query.equalTo == true)"
          }
        }
      }
    }
    
    要创建新产品,我首先将其推到“public”,然后使用返回的密钥创建私有记录

    //添加新产品
    db.ref(“产品/公共”).push(公共数据)
    。然后((数据)=>{
    key=data.key
    返回键
    })
    .然后((键)=>{
    db.ref('products/private').child(key).update(privateData)
    返回键
    })
    .然后(…)
    
    要获得产品,公共/未经验证的用户必须在公共场所查找
    isPublished
    。 管理员可以通过公共和私有子节点进行循环

    //检索产品-公共
    db.ref('products/public')。orderByChild('isPublished')。equalTo(true)。once('value'))
    。然后((数据)=>{
    让publicData=data.val()
    //对数据做点什么
    })
    //检索产品-管理员
    db.ref(‘产品’)。一次(‘值’)
    。然后((数据)=>{
    让publicData=data.child('public').val()
    让privateData=data.child('private').val()
    //对数据做点什么
    })
    
    谢谢你,弗兰克。但有两件事:1。您的注释是正确的,但代码示例并非如此。我可以通过将读取规则移动到“产品”下使其工作。但是2.现在,如果isPublic为true,“private”节点也可以被未经授权的用户读取。所以我想我必须把isPrivate转移到它自己的组中。让我们假设
    产品:{meta:{isPublic:true},private:{…}
    。但是我现在有点不知所措了,我只是更新了我的答案,删除了额外的级别。很抱歉复制/粘贴错误。一旦用户有权访问某个节点,他们就有权访问该节点下的所有数据。没有办法从他们可以读取的节点隐藏私有数据。您需要将私有数据存储在单独的顶级节点中,如下所示:
    // Firebase Rules
    {
      "rules": {
        "products" : {
          ".read": "auth.uid == '[admin user id]'",
          ".write": "auth.uid == '[admin user id]'",
    
          "public" : {
            ".indexOn": "isPublished",
            ".read": "(query.orderByChild == 'isPublished' && query.equalTo == true)"
          }
        }
      }
    }