使用Firebase Firestore我将聊天室详细信息存储在包含以下数据的文档中:
roomName
roomAvatar
createDate
isDeleted
我的应用程序和我的规则要求在文档的“创建”上设置这些字段。但是,我还想允许授权用户“更新”文档。
我已经进行了检查,只允许某些用户更新文档并验证他们不能修改像“createDate”这样的字段。但是,我似乎无法通过传递FiledValue.delete()或使用ref.set(objectMissingCreateDate)来创建强制授权用户不删除“createDate”字段的规则。
最后,如果客户端只尝试更新一个或两个字段,我认为不应要求客户端传递更新的所有数据字段。
我有一个“更新”规则如下:
allow update: if isAuthenticated() && isMemberOfRoom() &&
(
(!("roomName" in request.resource.data) ||
request.resource.data.roomName == resource.data.roomName ||
hasRoomPermission("UpdateRoom")) &&
(!("roomAvatar" in request.resource.data) ||
request.resource.data.roomAvatar == resource.data.roomAvatar ||
hasRoomPermission("UpdateRoom")) &&
(!("createDate" in request.resource.data) ||
request.resource.data.createDate == resource.data.createDate) &&
(!("isDeleted" in request.resource.data) ||
request.resource.data.isDeleted == resource.data.isDeleted ||
hasRoomPermission("DeleteRoom"))
);
主要问题是保护来自传递FieldValue.delete()或使用[Android] docRef.set()的授权用户的数据,同时缺少必需的值。
我甚至会接受关闭非管理员客户端的FieldValue.delete()和破坏性“设置”操作的功能。
在Doug和Puff的评论的帮助下,我意识到我做错了什么。
首先,我不知道只通过几个字段的更新(或带有合并选项的集合)将导致其余字段从数据库的request.resource
复制到resource
上。
其次,一组(没有合并)或传入FieldValue.delete()
将是request.resource
错过现有文档字段的唯一方式。
有了这些新知识,我将以前的规则更新为以下内容:
allow update: if isAuthenticated() && isMemberOfRoom() &&
(
("roomName" in request.resource.data &&
(request.resource.data.roomName == resource.data.roomName ||
hasRoomPermission("UpdateRoom"))) &&
("roomAvatar" in request.resource.data &&
(request.resource.data.roomAvatar == resource.data.roomAvatar ||
hasRoomPermission("UpdateRoom"))) &&
("createDate" in request.resource.data &&
request.resource.data.createDate == resource.data.createDate) &&
("isDeleted" in request.resource.data &&
(request.resource.data.isDeleted == resource.data.isDeleted ||
hasRoomPermission("DeleteRoom")))
);
这些新规则现在使createDate
锁定客户端,同时允许为通过权限测试的客户编辑roomName
,roomAvatar
和isDeleted
。它也不允许使用FieldValue.delete()
更新任何这些字段或调用docRef.set(object)
,其中对象缺少其中一个字段。