【发布时间】:2019-01-17 04:26:18
【问题描述】:
我的目标
我只想允许用户更新其他用户文档中的特定字段。
我的用户文档
/* BEFORE */
{
id: 'uid1',
profile: { /* a map of personal info */ },
connectedUsers: {
uid2: true,
uid3: true,
}
}
/* AFTER */
{
id: 'uid1',
profile: { /* a map of personal info */ },
connectedUsers: {
uid2: true,
uid3: true,
uid4: true, // <--- added.
}
}
请求
const selfUserId = 'uid4';
db.runTransaction(function(transaction) {
return transaction.update(userDocRef).then(function(userDoc) {
if (!userDoc.exists) { throw "Document does not exist!"; }
transaction.update(userDocRef, 'connectedUsers.${selfUserId}', true);
});
}
我对规则如何运作的理解:
request.resource.dara是entire目标文档after的变化。对于
update操作,上述内容仍然适用。我不太明白文档的含义:
对于只修改文档子集的更新操作 字段,
request.resource变量将包含 pending 操作后的文档状态。
我的规则:(见下方更新)
function existingData() { return resource.data }
function expectedData() { return request.resource.data }
- 检查更新后是否添加了请求者的
uid。
function isAddingRequester() {
return expectedData().connectedUsers[requesterId()] != null
}
- 检查更新后是否只有
1或0项添加到connectedUsers。0如果请求者已经在列表中。
function isAddingOneAtMost() {
return expectedData().connectedUsers.size() == existingData().connectedUsers.size() + 1
|| expectedData().connectedUsers.size() == existingData().connectedUsers.size()
}
- 检查用户文档的所有其他字段在更新后是否未更改。
function isNotChangingOtherFields() {
return expectedData().id == existingData().id
&& expectedData().profile == existingData().profile
}
我的问题
我对 Firestore 规则如何工作的理解是否正确?
pending document state上面引用的文档是什么意思?我的规则实施是否反映了我的意图?搜索了一下,发现模拟器可能有bug,一头雾水。
在我的
isNotChangingOtherFields函数中,我能否直接将profile对象与==运算符进行比较?
更新 - 2018 年 1 月 17 日下午 3 点
删除了existingData() 和expectedData()。
function isAddingRequester() {
return request.resource.data.connectedUsers[requesterId()] != null
}
function isAddingOneAtMost() {
return (request.resource.data.connectedUsers.size() == resource.data.connectedUsers.size() + 1)
|| (request.resource.data.connectedUsers.size() == resource.data.connectedUsers.size()) // NOTE: if the requester is already in the list.
}
function isNotChangingOtherFields() {
return request.resource.data.profile == resource.data.profile
&& request.resource.data.id == resource.data.id
}
function isNotAddingOtherFields() {
return request.resource.data.size() == resource.data.size()
}
调试结果
有趣的是,模拟器和生产中的结果不相同。
// PASSED in simulator & production:
allow update: if isAddingRequester();
// PASSED in simulator but NOT production:
allow update: if isNotChangingOtherFields();
// PASSED in simulator but NOT production:
allow update: if isNotAddingOtherFields();
// FAILED in both simulator AND production:
allow update: if isAddingOneAtMost();
// NOTE: inserted 2 mock data before update.
// PASSED in simulator:
allow update: if resource.data.connectedUsers.size() == 2;
// FAILED in simulator:
allow update: if request.resource.data.connectedUsers.size() == 3;
// PASSED in simulator:
allow update: if request.resource.data.connectedUsers.size() == 1;
问题
如果request.resource是更新后的文档,为什么是request.resource.data.connectedUsers.size()而不是3(现有2个+新增1个)?
相关发现(来自模拟器)
如果我有一个函数:
expectedData() { return request.resource.data }
而我得到了如此意想不到的结果:
// PASSED:
allow update: if request.resource.data.id == expectedData().id;
// FAILED if the order is changed.
allow update: if expectedData().id == request.resource.data.id;
【问题讨论】:
-
一篇文章中有太多问题。 “我对规则如何工作的理解:request.resource.dara 是更改后的整个目标文档。对于更新操作,上述内容保持不变。”那是正确的。文档也是这么说的(使用“待定”表示您所谓的“更改后”),尽管我承认它可能更清楚。
-
您的规则中的
expectedData()是什么?另外:代码有什么问题?它是否拒绝您要允许的写入?还是允许您想要拒绝的写入? -
您是否考虑过分解总体规则的每一部分并单独测试,完全相互独立,而不是尝试一次调试整个事情?
-
@FrankvanPuffelen 感谢您的解释。我在帖子底部添加了一些调试更新。
-
@DougStevenson 感谢您的建议g,我已经进行了一些调试并在我的帖子中进行了更新。
标签: google-cloud-firestore firebase-security