我有一个Google Firestore实时数据库,其中包含标志isPublic
。如果设置为true
,则未经身份验证的用户可以读取子节点details
。如果设置为false
,则该记录只能由一个(目前)经过身份验证和授权的用户访问。
授权用户是唯一具有写许可权的人。
此外,子节点private
始终仅向一个授权用户授予访问权限。
我研究过的解决方案基于基于查询的规则https://firebase.google.com/docs/database/security/securing-data#query-based_rules
不幸的是,即使是授权用户,我也收到permission_denied
的回复。
除了信息:这是在使用Firebase SDK的Vue JS项目中。
这是我的数据库示例。
第一个产品应该对未经身份验证的用户具有对details
的读取权限,但对private
则没有读取权限。
通过强制用户运行查询dbRef.orderByChild('isPublic').equalTo(true)
"products": {
"-pushIdxyz1" : {
"isPublic" : true,
"private" : {
"notes" : "lorem ipsum always private",
"soldDate" : ""
},
"details" : {
"imageURL" : "https://firebasestorage.imagexyz",
"keywords" : "this, that",
"title" : "Public product title",
"workCategory" : "hardware",
},
},
"-pushIdxyz2" : {
"isPublic" : false,
"private" : {
"notes" : "lorem ipsum always private",
"soldDate" : ""
},
"details" : {
"imageURL" : "https://firebasestorage.imagexyz",
"keywords" : "this, that",
"title" : "Secret product title",
"workCategory" : "hardware",
},
}
}
我的无效规则
"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')
.then(...)
此查询(仅适用于授权用户)应授予对所有数据的读取权限
firebase.database().ref('products').once('value')
.then(...)
在当前设置下,无论是否以授权用户身份登录,我都对查询“权限被拒绝”。
答案 0 :(得分:1)
如果希望用户能够从products
节点进行读取,则需要在该节点上具有.read
规则。并且由于您只想在对公共产品查询时才允许读取,因此您应该验证该特定查询。
类似这样的东西:
"rules": {
"products": {
".indexOn": "isPublic",
".read": "(query.orderBy == 'isPublic' && query.equalTo == true)
|| auth.uid == '[admin user id]'"
}
}
所以:
/products
的所有读取均被拒绝。orderBy
字段。请注意,您在.read
上声明的附加private
规则在这里是没有意义的,因为无论如何,同一用户已经获得了整个`products节点的读取权限。
答案 1 :(得分:0)
Franks答案将我引向正确的方向(谢谢!),但我决定自己发布一个更完整的答案。
这是数据结构。请注意,我将“ isPublic”更改为“ isPublished”。 现在,“产品”包含两个子节点:“私有”和“公共”。两者都使用相同的密钥。
// 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)"
}
}
}
}
要创建新产品,我首先将其设置为“公开”,然后使用返回的密钥创建私人记录
// Add new product
db.ref('products/public').push(publicData)
.then((data) => {
key = data.key
return key
})
.then((key) => {
db.ref('products/private').child(key).update(privateData)
return key
})
.then( ... )
要获取产品,公共/未经身份验证的用户必须在公共场所寻找isPublished
。
管理员可以遍历公共和私有子节点
// Retrieve products - Public
db.ref('products/public').orderByChild('isPublished').equalTo(true).once('value')
.then((data) => {
let publicData = data.val()
// Do something with the data
})
// Retrieve products - Admin
db.ref('products').once('value')
.then((data) => {
let publicData = data.child('public').val()
let privateData = data.child('private').val()
// Do something with the data
})