【发布时间】:2018-10-25 06:29:19
【问题描述】:
我有一个用户集合,其中每个文档都包含一个名称字段和一个访问映射。
"users" :[
{
"mHbVq5TUY7brlleejClKm71NBGI2": {
"name": "Bob Johnson",
"access": {
"X0w1VaVIljR1Nc5u3Sbo" : true
}
}
]
我希望 Firestore 规则允许仅当新文档尚不存在且执行该操作的人已验证其电子邮件时才允许创建新文档。对于更新,只有拥有该节点的用户才能执行更新,名称必须是字符串,并且访问映射不能更改。我在模拟器中测试了我的更新并创建了规则,它们按预期工作。但是,当我运行 .set() 时,它会完全覆盖我的整个节点并删除我不可能发生的访问映射。我假设 .set() 实际上正在执行更新,因此符合我的更新标准。那么,如何防止有人完全覆盖我的节点。在此先感谢...下面的代码。
---代码执行覆盖
db.collection("users").doc("mHbVq5TUY7brlleejClKm71NBGI2").set(
{
name: "Bill Swanson",
}
).catch(err => {
console.log(err.message)
})
---规则
function incomingData() {
return request.resource.data
}
function emailVerified() {
return request.auth.token.email_verified;
}
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
function userExists(user_Id) {
return exists(/databases/$(database)/documents/users/$(user_Id));
}
allow create: if !userExists(userId) && emailVerified();
allow update: if request.auth.uid == userId
&& !('access' in incomingData())
&& request.resource.data.name is string;
allow read: if request.auth.uid != null;
}
}
}
【问题讨论】:
-
根据此链接 (cloud.google.com/nodejs/docs/reference/firestore/0.17.x/…),如果文档已经存在,.set 实际上会执行更新,但它显然忽略了我的更新规则并覆盖整个文档而不是合并。想知道是否有人对此有解决方法吗?我已经看到很多使用这种方法来防止覆盖的示例,并且似乎它们会产生类似的结果 (gist.github.com/mcdonamp/f18b1991f74f7a266e0d15f31d46d637)
-
旋转我的轮子后,我在文档中发现了一个非常微妙的区别 (firebase.google.com/docs/firestore/security/rules-conditions)。 “对于只修改文档字段子集的更新操作,request.resource 变量将包含操作后的待处理文档状态。”因此,当我将incomingData 与existingData 进行比较时,它实际上不是incomingData。为什么没有更多的专家做出这种区分?这种类型的问题到处都是,专家说request.resource.data是正在发送的数据?
-
从请求中获取实际incomingData 的唯一真正方法是查看request.writeFields,它已被弃用并且不能在模拟器上使用。实际上,我会写一整篇关于我追踪此事的经验的文章,但显然我无法提出任何新问题,因为我受到限制。不知道为什么会这样。我也不能像我一样去回答无数的问题,因为我没有声望点。好吧,我当然希望其中一些人能回答这些问题。人们被糟糕的建议和演示误导了。
标签: firebase google-cloud-firestore firebase-security