对于我的生活,我不明白为什么下面的结果是一个允许写的false
。假设我的users
集合为空开始,并且我正在从我的角度前端编写以下形式的文档:
{
displayName: 'FooBar',
email: 'foo.bar@example.com'
}
我现在的安全规则:
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
function isAdmin() {
return resource.data.role == 'ADMIN';
}
function isEditingRole() {
return request.resource.data.role != null;
}
function isEditingOwnRole() {
return isOwnDocument() && isEditingRole();
}
function isOwnDocument() {
return request.auth.uid == userId;
}
allow read: if isOwnDocument() || isAdmin();
allow write: if !isEditingOwnRole() && (isOwnDocument() || isAdmin());
}
}
}
一般来说,我不希望任何用户能够编辑他们自己的角色。普通用户可以编辑自己的文档,管理员也可以编辑任何人的文档。
为isEditingRole()
设置false
会给出预期的结果,所以我把范围缩小到了这个表达式。
写的一直是假的,我无法确定原因。任何想法或修正都是有帮助的!
编辑1
我尝试过的事情:
function isEditingRole() {
return request.resource.data.keys().hasAny(['role']);
}
和
function isEditingRole() {
return 'role' in request.resource.data;
}
和
function isEditingRole() {
return 'role' in request.resource.data.keys();
}
编辑2
请注意,最终,管理员将为用户设置一个角色,因此最终可能会在文档中存在一个角色。这意味着,根据下面的修复文档,请求将有一个role
密钥,即使不在原始请求中。
将资源中存在的请求中未提供的字段添加到
request.resource.data
中。规则可以通过将request.resource.data.foo
与resource.data.foo
进行比较来测试字段是否被修改,同时知道resource
中的每个字段也将出现在request.resource
中,即使它不是在写请求中提交的。
据此,我认为“编辑1”中的三个选项被排除在外。我确实尝试过request.resource.data.role != resource.data.role
的建议,但这也不起作用.我茫然不知所措,开始怀疑Firestore中是否真的有一个bug。
发布于 2018-01-11 11:20:16
因此,最后,我似乎假设resource.data.nonExistentField == null
会返回false
,而实际上它会返回一个Error
(根据这和我的测试)。所以我最初的解决方案可能就是碰到了这个问题。这是令人费解的,因为根据医生们,相反的方法应该有效,但也许文档是指一个“不存在”的值,而不是关键--一个微妙的区别。
我仍然没有达到100%的清晰度,但这是我最终成功的结果:
function isAddingRole() {
return !('role' in resource.data) && 'role' in request.resource.data;
}
function isChangingRole() {
return 'role' in resource.data && 'role' in request.resource.data && resource.data.role != request.resource.data.role;
}
function isEditingRole() {
return isAddingRole() || isChangingRole();
}
另一件仍然令我困惑的事情是,根据文档,我不应该需要&& 'role' in request.resource.data
部件在isChangingRole()
中,因为它应该由Firestore自动插入。尽管情况似乎并非如此,因为删除它会导致我的写权限问题失败。
可能会通过将写入到create
、update
和delete
部件中,而不是仅通过allow write: if !isEditingOwnRole() && (isOwnDocument() || isAdmin());
来澄清/改进。
发布于 2018-01-09 14:43:26
如果您创建一个自定义函数来检查更新,那么您的规则将更加可读性和可维护性。例如:
service cloud.firestore {
match /databases/{database}/documents {
function isUpdatingField(fieldName) {
return (!(fieldName in resource.data) && fieldName in request.resource.data) || resource.data[fieldName] != request.resource.data[fieldName];
}
match /users/{userId} {
// Read rules here ...
allow write: if !isUpdatingField("role") && !isUpdatingField("adminOnlyAttribute");
}
}
}
发布于 2018-02-21 18:55:44
我用writeFields
解决了这个问题。请试试这个规则。
allow write: if !('role' in request.writeFields);
在我的例子中,我使用list
来限制更新字段。它也很管用。
allow update: if !(['leader', '_created'] in request.writeFields);
https://stackoverflow.com/questions/48176704
复制