使用PERMISSION_DENIED进行Firebase更新结果而不违反规则 - 使用解决方案

时间:2015-07-29 19:48:07

标签: firebase firebase-security

我认为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())"
  }
}

现在有效。

2 个答案:

答案 0 :(得分:3)

documentation for newData说:

  

RuleDataSnapshot,对应于允许写入时将产生的数据。

因此它不仅包含更新,它包含数据,因为如果允许这样写,它将存在于该位置。

答案 1 :(得分:0)

此问题的

解决方法是扩展规则,以便在旧值等于新值时返回true:

"profile": {
  "$appUserId": {
    ".read": "auth.uid !== null",
    ".write": "(!newData.child('photo').exists() || newData.child('photo').val() == data.child('photo').val())"
  }
}

但是,我认为它不应该像这样工作,应该改变。