我正在设置Firestore安全规则,但是遇到一个问题,在这个问题中,我想限制使用hasOnly函数仅更新文档中的一个特定字段。问题是我一直在使用模拟器获得“被拒绝”的结果。我肯定在做一些简单的错误...我试图防止有人可以更新文档中除update_requested_time
以外的其他字段,但是允许他们更新此特定字段。
在hasOnly()上使用Firestore文档中的示例— ['a', 'b'].hasOnly(['b', 'a']) == true
时,规则将返回true。但是,当我使用自己的方法时,并没有这样做,因此我认为request.resource.data.keys()
中出现了问题。
特定场景中的特定规则定位字段:
match /scenarios/{scenario} {
allow read: if true;
allow update: if request.auth.uid != null
&& request.resource.data.keys().hasOnly(['update_requested_time']) == true;
我正在发送的模拟器请求(通过身份验证更新):
{"__name__":"/databases/(default)/documents/scenarios/test1","data":{"update_requested_time":"2019-02-05T11:00:00.000Z"}}
我的完整规则:
service cloud.firestore {
match /databases/{database}/documents {
match /scenarios/{scenario} {
allow read: if true;
allow update: if request.auth.uid != null
&& request.resource.data.keys().hasOnly(['update_requested_time']) == true;
match /comments/{comment} {
allow read: if true;
allow create: if request.auth.uid != null;
allow delete,update: if request.auth.uid != null && request.auth.uid == resource.data.user;
}
match /outputs/{tile} {
allow read: if true;
}
match /mutations/{tile} {
allow read: if true;
allow create,update: if request.auth.uid != null;
}
}
match /users/{user} {
allow read: if true;
allow update: if request.auth.uid != null && request.auth.uid == user;
}
}
}
答案 0 :(得分:1)
request.resource.data
不包含请求数据本身,而是包含写操作之后的资源的新版本。因此检查失败。
request.resource
上的Firestore文档:
新资源值,仅在写入请求中出现。
答案 1 :(得分:1)
现在看来正确的方法是
request.resource.data.diff(resource.data).affectedKeys().hasOnly(["update_requested_time"])
从this对话中找到
答案 2 :(得分:0)
也许我误解了这一点,但这不是一种解决方案,不能让您的规则在request.data
和request.resource.data
之间进行深度比较以确认仅一个字段发生了变化吗?
也许有一种更清洁的方法,但是呢:
import _ from "lodash";
service cloud.firestore {
match /databases/{database}/documents {
function onlyRequestTimeChanged(currValue, newValue) {
let newCopy = _.cloneDeep(newValue)
newCopy.update_requested_time = currValue.update_requested_time
return _.isEqual(currValue, newCopy)
}
match /scenarios/{scenario} {
allow read: if true;
allow update: if onlyRequestTimeChanged(request.resource,data, request.data)
// ...
}