firebase - Firestore 安全规则:使用 Set.hasAny() 时出现空值错误
问题描述
我有一个user
包含两个字段memberOf
和managerOf
(即,一个组织的集合;两者都是文档 ID 数组)的集合。
我想限制经理仅列出属于他们管理的组织的成员的用户。
在 JS 中,它会是这样的:
const memberOf = [1, 2, 3, 4, 5]
const managerOf = [6, 7, 1, 9, 0]
console.log(memberOf.some(el => managerOf.includes(el))) // returns true
这是我到目前为止所拥有的:
function isSignedIn() {
return request.auth.uid != null
}
function isAdmin() {
return isSignedIn() && 'admin' in request.auth.token && request.auth.token.admin
}
match /users/{userId} {
allow get: if isSignedIn() && (request.auth.uid == userId || isAdmin());
allow list: if isAdmin() || ???; // how can I express the above condition?
allow write: if isAdmin();
}
这就是查询:
const unsubscribe = db.collection('users')
.where('memberOf', 'array-contains', organisationId)
.orderBy('email', 'asc')
.onSnapshot(snap => {
console.log(`Received query snapshot of size ${snap.size}`)
var docs = []
snap.forEach(doc => docs.push({ ...doc.data(), id: doc.id }))
actions.setMembers(docs)
}, error => console.error(error))
首先,我想organisationId
在安全规则中使用来自请求的,但它不可用,因为它不是写操作(https://firebase.google.com/docs/reference/rules/rules.firestore.Request#resource)
我想过:
function hasMemberManagerRelationship(userId) {
return isSignedIn() && get(/databases/$(database)/documents/users/$(userId)).data.memberOf in get(/databases/$(database)/documents/users/$(request.auth.uid)).data.managerOf
}
match /users/{userId} {
allow get: if isSignedIn() && (request.auth.uid == userId || isAdmin());
allow list: if isAdmin() || hasMemberManagerRelationship(userId);
allow write: if isAdmin();
}
或者
function hasMemberManagerRelationship(userId) {
return isSignedIn() && get(/databases/$(database)/documents/users/$(userId)).data.memberOf.toSet().hasAny(get(/databases/$(database)/documents/users/$(request.auth.uid)).data.managerOf.toSet())
}
(https://firebase.google.com/docs/reference/rules/rules.Set#hasAny)
但它不工作,我有错误FirebaseError: Null value error. for 'list' @ L27
。最重要的是,这可能会产生大量额外的读取操作(未在计费方面进行优化)。
我可以执行以下操作:
allow list: if isAdmin() || (isManagerOf('jJXLKq7p9wWSNLsHcVIn') && 'jJXLKq7p9wWSNLsHcVIn' in resource.data.memberOf);
组织的 id在哪里jJXLKq7p9wWSNLsHcVIn
(并在查询中使用),但我不知道如何从请求“上下文”中检索 id..
任何帮助,将不胜感激!
解决方案
好的。首先,感谢@Doug Stevensondebug()
在另一篇文章中提到!我不知道它的存在,它摇摆不定!
debug(resource.data.memberOf)
调试日志中的结果是:
constraint_value {
simple_constraints {
comparator: LIST_CONTAINS
value {
string_value: "jJXLKq7p9wWSNLsHcVIn"
}
}
}
LIST_CONTAINS
强迫我看看列表:https ://firebase.google.com/docs/reference/rules/rules.List#hasAny
(事实上,它确实存在,但在我的情况下不起作用)toSet()
不适用于列表,但列表已经具有该hasAny()
功能。
最后,这条规则有效:
function hasMemberManagerRelationship() {
return isSignedIn() && resource.data.memberOf.hasAny(getUser(request.auth.uid).data.managerOf)
}
现在我只是想知道是否getUser(request.auth.uid).data.managerOf
以某种方式缓存(1 读取多个用户条目)或每次重新运行(100 个用户,100 次额外读取)。
对此有什么想法吗?
我真诚地希望这是第一个案例^^
推荐阅读
- linux - 无法使用 usermod 将组附加到用户组
- css - flexbox 拒绝按照我的意图证明内容的合理性
- javascript - 创建一个独特组合的数组
- mongodb - 从 linux 连接 mongo 数据库副本集的问题,单实例运行正常。使用 .net 核心 mongo 驱动程序
- php - 支付 WooCommerce 订单时如何重新保存可变产品的所有变体?
- ios - TPPDF ios中每一页的页脚
- server - 如何在 HAproxy 中设置自定义数量的备份后端服务器?
- javascript - 如何将照片注入 Gatsby 网站?
- sql - 案例表达式给出“日期数据类型到日期时间数据类型的转换导致超出范围的值”。
- javascript - 在 JavaScript 中合并两个多维数组的口袋