PERMISSION_DENIED 不违反规则的 Firebase 更新结果 - 附解决方案
Firebase update result with PERMISSION_DENIED without breaking the rules - with solution
我认为这可能是 update()
函数中的错误,在 Firebase 中特定使用规则。
我对 profile
节点有以下规则:
"profile": {
"$appUserId": {
".read": "auth.uid !== null",
".write": "!newData.child('photo').exists()"
}
}
(为清楚起见,我省略了 .write
规则中的身份验证)
用户 profile
包含 photo
但只能通过后端更新。客户无法设置此信息。
我正在使用 update()
函数来设置配置文件数据。当我创建配置文件(新节点)时,一切正常。但是配置文件是在每个 update()
调用结果中创建的 PERMISSION_DENIED。我是在一次调用中更新一个字段还是多个字段都没有关系。自然地,传入对象中没有 photo
键。此外,set()
函数在相同条件下完美运行(但删除任何其他字段 - 包括 photo
)。
当我删除 .write
规则(并只保留身份验证检查)时,它正在工作。所以我开始怀疑。对我来说,在 update()
调用期间,它看起来像是在内部读取现有数据,将其与传入数据合并,用新值覆盖旧值,然后尝试将其全部保存。在它实际保存数据之前有一个规则检查所以 - 在这一点上 - 它会导致错误。我想它应该在合并数据之前进行规则检查(假设它像我上面描述的那样工作)。
编辑。
重现问题:
1) 设置代码:
var appId = 'APP ID', appUserIdKey = 'test'; //appUserIdKey can be whatever you want
//data to be saved
var profileData = {
name: "Pawel"
age: 31,
photo: 'image.jpg'
};
2) 由于在我的环境中只有后端使用服务密钥将数据保存到 profile/[appUserIdKey]/photo
,因此您必须暂时删除 .write
条规则。
现在规则应该是这样的:
"profile": {
"$appUserId": {
".read": "auth.uid !== null",
".write": "auth.uid !== null"
}
}
3) 运行 创建配置文件的代码
var ref = new Firebase('https://'+appId+'.firebaseio.com/profile/' + appUserIdKey);
ref.update(profileData);
4) 现在,恢复规则。
"profile": {
"$appUserId": {
".read": "auth.uid !== null",
".write": "(auth.uid !== null) && (!newData.child('photo').exists())"
}
}
5) 再次尝试更新个人资料:
var ref = new Firebase('https://'+appId+'.firebaseio.com/profile/' + appUserIdKey);
ref.update({'age':18});
您将收到一条错误消息
6) 将规则更改为以下内容:
"profile": {
"$appUserId": {
".read": "auth.uid !== null",
".write": "(auth.uid !== null) && (!newData.child('photo').exists()) || newData.child('photo').val() == data.child('photo').val())"
}
}
现在有效。
此问题的解决方法 是扩展规则,因此如果旧值等于新值,它将 return 为真:
"profile": {
"$appUserId": {
".read": "auth.uid !== null",
".write": "(!newData.child('photo').exists() || newData.child('photo').val() == data.child('photo').val())"
}
}
不过,我觉得不应该这样,应该改一下。
A RuleDataSnapshot corresponding to the data that will result if the write is allowed.
因此它不仅包含更新,还包含数据,因为如果允许此写入,它将存在于该位置。
我认为这可能是 update()
函数中的错误,在 Firebase 中特定使用规则。
我对 profile
节点有以下规则:
"profile": {
"$appUserId": {
".read": "auth.uid !== null",
".write": "!newData.child('photo').exists()"
}
}
(为清楚起见,我省略了 .write
规则中的身份验证)
用户 profile
包含 photo
但只能通过后端更新。客户无法设置此信息。
我正在使用 update()
函数来设置配置文件数据。当我创建配置文件(新节点)时,一切正常。但是配置文件是在每个 update()
调用结果中创建的 PERMISSION_DENIED。我是在一次调用中更新一个字段还是多个字段都没有关系。自然地,传入对象中没有 photo
键。此外,set()
函数在相同条件下完美运行(但删除任何其他字段 - 包括 photo
)。
当我删除 .write
规则(并只保留身份验证检查)时,它正在工作。所以我开始怀疑。对我来说,在 update()
调用期间,它看起来像是在内部读取现有数据,将其与传入数据合并,用新值覆盖旧值,然后尝试将其全部保存。在它实际保存数据之前有一个规则检查所以 - 在这一点上 - 它会导致错误。我想它应该在合并数据之前进行规则检查(假设它像我上面描述的那样工作)。
编辑。
重现问题:
1) 设置代码:
var appId = 'APP ID', appUserIdKey = 'test'; //appUserIdKey can be whatever you want
//data to be saved
var profileData = {
name: "Pawel"
age: 31,
photo: 'image.jpg'
};
2) 由于在我的环境中只有后端使用服务密钥将数据保存到 profile/[appUserIdKey]/photo
,因此您必须暂时删除 .write
条规则。
现在规则应该是这样的:
"profile": {
"$appUserId": {
".read": "auth.uid !== null",
".write": "auth.uid !== null"
}
}
3) 运行 创建配置文件的代码
var ref = new Firebase('https://'+appId+'.firebaseio.com/profile/' + appUserIdKey);
ref.update(profileData);
4) 现在,恢复规则。
"profile": {
"$appUserId": {
".read": "auth.uid !== null",
".write": "(auth.uid !== null) && (!newData.child('photo').exists())"
}
}
5) 再次尝试更新个人资料:
var ref = new Firebase('https://'+appId+'.firebaseio.com/profile/' + appUserIdKey);
ref.update({'age':18});
您将收到一条错误消息
6) 将规则更改为以下内容:
"profile": {
"$appUserId": {
".read": "auth.uid !== null",
".write": "(auth.uid !== null) && (!newData.child('photo').exists()) || newData.child('photo').val() == data.child('photo').val())"
}
}
现在有效。
此问题的解决方法 是扩展规则,因此如果旧值等于新值,它将 return 为真:
"profile": {
"$appUserId": {
".read": "auth.uid !== null",
".write": "(!newData.child('photo').exists() || newData.child('photo').val() == data.child('photo').val())"
}
}
不过,我觉得不应该这样,应该改一下。
A RuleDataSnapshot corresponding to the data that will result if the write is allowed.
因此它不仅包含更新,还包含数据,因为如果允许此写入,它将存在于该位置。