我正在try 设置FiRestore规则,允许用户仅更新嵌套对象中的某些字段.我知道如果它是顶级密钥,我们可以简单地使用如下内容:
allow update: if request.auth.uid == userID &&
request.resource.data.diff(resource.data).affectedKeys().hasOnly(["key1", "key2"]);
然而,我遇到了一个限制对象内部键的更新的问题,让我们称之为"omeData".这就是我试过的,看起来合乎逻辑,但不起作用:
allow update: if request.auth.uid == userID &&
request.resource.data.diff(resource.data).affectedKeys().hasOnly("someData", "otherData") &&
(!("someData" in request.resource.data.keys()) ||
(request.resource.data["someData"].diff(resource.data["someData"])
.affectedKeys().hasOnly(["key1", "key2"]));
或者像这样:
allow update: if request.auth.uid == userID &&
request.resource.data.diff(resource.data).affectedKeys().hasOnly("someData", "otherData") &&
(!("someData" in request.resource.data.keys()) ||
(request.resource.data.someData.diff(resource.data.someData)
.affectedKeys().hasOnly(["key1", "key2"]));
两种方法都不管用.
有办法保护嵌套字段吗?
谢谢!
我try 在测试环境中使用"mocha"进行测试,try 使用Real FiRestore,并try 将此逻辑放在单独的函数中.毫无办法.
Firebase文档只说明文档的顶级密钥. 我在这里找到了一个解决方案,类似于我的第一个示例,但在现实生活中似乎不起作用.
我做错什么了吗?
Update with more specific details个
以下是我最初的规则(在一款出租车预订应用上工作):
allow update: if request.auth.uid == userID &&
editOnlyFields(["name", "phoneNumber", "driversData", "waitingDriverApproval", "lastUpdate"]) &&
request.resource.data.lastUpdate == request.time &&
(!("name" in request.resource.data.keys()) ||
request.resource.data.name is string) &&
(!("phoneNumber" in request.resource.data.keys()) ||
request.resource.data.phoneNumber is string) &&
(!("waitingDriverApproval" in request.resource.data.keys()) ||
(request.resource.data.waitingDriverApproval is bool && request.resource.data.waitingDriverApproval == true)) &&
//nested driversData (pain in the butt)
(!("driversData" in request.resource.data.keys()) ||
(request.resource.data.driversData.keys().hasOnly(["licensingAuthority", "amountOfVehicles", "DVLACheckCode", "DVLALicence", "PHBadge", "PHDriversLicence"])) &&
(!("licensingAuthority" in request.resource.data.driversData.keys()) ||
request.resource.data.driversData.licensingAuthority is string) &&
(!("amountOfVehicles" in request.resource.data.driversData.keys()) ||
request.resource.data.driversData.amountOfVehicles is int) &&
(!("DVLACheckCode" in request.resource.data.driversData.keys()) ||
(request.resource.data.driversData.DVLACheckCode.keys().hasOnly(["code", "pending"]) &&
isValidDVLACheckCode(request.resource.data.driversData.DVLACheckCode))) &&
(!("DVLALicence" in request.resource.data.driversData.keys()) ||
(request.resource.data.driversData.DVLALicence.keys().hasOnly(["downloadUrl", "pending"]) &&
isValidDriversPaperwork(request.resource.data.driversData.DVLALicence))) &&
(!("PHBadge" in request.resource.data.driversData.keys()) ||
(request.resource.data.driversData.PHBadge.keys().hasOnly(["downloadUrl", "pending"]) &&
isValidDriversPaperwork(request.resource.data.driversData.PHBadge))) &&
(!("PHDriversLicence" in request.resource.data.driversData.keys()) ||
(request.resource.data.driversData.PHDriversLicence.keys().hasOnly(["downloadUrl", "pending"]) &&
isValidDriversPaperwork(request.resource.data.driversData.PHDriversLicence))));
}
function editOnlyFields(allowedFields) {
return request.resource.data.diff(resource.data).affectedKeys().hasOnly(allowedFields);
}
一切都很顺利,直到我开始从事管理部分的工作.管理员具有身份验证令牌自定义声明isBoss: true
如果isBoss(),则规则允许读写
match /{document=**} {
allow read, write: if isBoss();
}
function isBoss() {
return request.auth.token.isBoss == true;
}
现在,对于原始规则,我面临着一个问题--当管理员更改用户driversData
内的任何内容时,用户不会被授权做一些事情,比如approvedDriver: true
,那么用户就不能更新他们的driversData
,因为请求对象包含更新后出现的所有字段.
因此,我从替换下面这行开始了规则更新:
request.resource.data.driversData.keys().hasOnly(allowedFields)
这一个:
(editOnlyFieldsNested("driversData", ["licensingAuthority", "amountOfVehicles", "DVLACheckCode", "DVLALicence", "PHBadge", "PHDriversLicence"]))
哪里
function editOnlyFieldsNested(nestedObj, allowedFields) {
return request.resource.data[nestedObj].diff(resource.data[nestedObj]).affectedKeys().hasOnly(allowedFields);
}
当我运行FiRestore模拟器时,以下函数失败:
it("Can update a user document only with allowed fields", async () => {
await testEnv.withSecurityRulesDisabled((context) => {
return context.firestore().collection("users").doc(myId).set({
name: "User Abc",
email: "abs@ruxus.taxi",
createdAt: serverTimestamp(),
});
});
const testDoc = myUser.firestore().collection("users").doc(myId);
await assertSucceeds(
testDoc.update({
name: "New Name",
phoneNumber: "after",
driversData: { amountOfVehicles: 1, licensingAuthority: "Bristol" },
lastUpdate: serverTimestamp(),
})
);
});
如果我用旧规则(没有MapDiff)运行它,它就通过了.
如果我使用带有editOnlyFieldsNested()
的新规则,它只有在我注释掉driversData
属性时才能通过,否则它会给我一个错误:
Can update a user document only with allowed fields:
FirebaseError: 7 PERMISSION_DENIED:
Property isBoss is undefined on object. for 'update' @ L8, evaluation error at L17:24 for 'update' @ L17, Property isBoss is undefined on object. for 'update' @ L8, Property driversData is undefined on object. for 'update' @ L17
也许它可以在驱动程序上做一些事情对象上未定义的数据... 为什么? 我被困在这个上面好几天了,我的笔记本满是泪水..
如有任何建议,不胜感激.