我的应用程序将用户的角色(订阅者,编辑者或管理员)存储为Firestore用户集合中用户文档内的“角色”映射。角色图如下:
// Roles map for a subscriber
{
subscriber: true
}
// Roles map for a editor
{
editor: true
}
// Roles map for administrator
{
administrator: true
}
我还可以根据需要在用户文档的角色图中放置多个(或全新的)角色字段。
我希望用户能够更新其个人资料,而又不能更改角色图。因此,对于安全规则,我尝试通过检查用户是所有者,以及之前和之后的角色是否相同来确保这一点。但是,在尝试更新时,总是会出现权限错误。规则如下:
match /users/{userUid} {
allow update: if
(
isOwner(userUid) &&
(
(request.resource.data.roles.administrator == resource.data.roles.administrator) &&
(request.resource.data.roles.editor == resource.data.roles.editor) &&
(request.resource.data.roles.subscriber == resource.data.roles.subscriber)
)
);
}
第一个isOwner(user)
条件如下:
function isOwner(uid) {
return (isSignedIn() && (request.auth.uid == uid));
}
我有信心这一部分可以正常工作,因为当我只运行它时,它就可以正常工作。
我怀疑我的问题可能是在写入之前或之后不存在某个角色字段(例如,订户)的情况下,它没有通过相等性检查。因此,我还尝试添加一个条件,以允许现有对象不具有该字段,但仍然不起作用:
match /users/{userUid} {
allow update: if
(
isOwner(userUid) &&
(
(!request.resource.data.roles.administrator || request.resource.data.roles.administrator == resource.data.roles.administrator) &&
(!request.resource.data.roles.editor || request.resource.data.roles.editor == resource.data.roles.editor) &&
(!request.resource.data.roles.subscriber || request.resource.data.roles.subscriber == resource.data.roles.subscriber)
)
);
}
在此先感谢您的帮助。
更新1
我使用writeFields
found是一个更简单的解决方案,该解决方案有效,但是不建议使用writeFields,因此这不是一个长期解决方案:
allow update: if isOwner(userUid) && !('roles' in request.writeFields)
同样,writeFields已被弃用,因此不应使用。
更新2
此解决方案最终为我工作,用符合我的情况的角色替换了角色:https://stackoverflow.com/a/48214390/4407512
答案 0 :(得分:1)
您现在可以使用地图差异来解决此问题,而无需使用不推荐使用的'writeFields'
allow update: if isOwner(userUid) && !('roles' in request.resource.data.diff(resource.data).affectedKeys());
答案 1 :(得分:0)
request.resource.data
是一个Map类型的对象。如您所说,可以确保属性始终存在,或者可以在使用属性之前检查该属性是否存在于Map中。 Map对象上的in
操作将使您知道是否存在属性。有关更多详细信息,请参见Map上的文档。
"administrator" in request.resource.data // true if administrator property exists