Firebase数据库快速入门处理计数的方式是否安全?

时间:2016-06-21 20:42:33

标签: android firebase firebase-realtime-database

我想为喜欢的文章创建一个增量字段。

我指的是这个链接:https://firebase.google.com/docs/database/android/save-data#save_data_as_transactions

在示例中,有增量字段的代码:

if (p.stars.containsKey(getUid())) {
    // Unstar the post and remove self from stars
    p.starCount = p.starCount - 1;
    p.stars.remove(getUid());
} else {
    // Star the post and add self to stars
    p.starCount = p.starCount + 1;
    p.stars.put(getUid(), true);
}

但我怎么能确定用户是否已经喜欢/不喜欢这篇文章?

在这个例子中,用户(黑客)可能会清除这样的全明星地图,无论如何它都会保存:

p.stars = new HashMap<>();

它会破坏已经喜欢它的其他用户的逻辑。

我甚至认为你不能为此制定规则,尤其是“减少计数”行动。

任何帮助,建议?

1 个答案:

答案 0 :(得分:25)

安全规则可以做一些事情:

  • 确保用户只能将自己的uid添加/删除到stars节点

    "stars": {
      "$uid": {
        ".write": "$uid == auth.uid"
      }
    }
    
  • 确保用户在将starCount添加到uid节点或从中移除时stars只能更改starCount

  • 确保用户只能将starCount增加/减少1

即使有这些,拥有一个确保stars等于stars节点中的uid数量的安全规则确实仍然很棘手。我鼓励你尝试一下,并分享你的结果。

我看到大多数开发人员处理这个问题的方式是:

  • 在客户端上开始计数(如果stars节点的大小不是太大,这是合理的)。
  • 在服务器上运行受信任的进程,将starCount聚合到votes: { uid1: true, uid2: true, }, voteCount: 2 。它可以使用child_added / child_removed事件来递增/递减。

更新:使用工作示例

我写了一个投票系统的实例。数据结构是:

{
  "/votes/uid3": true,
  "voteCount": 3
}

当用户投票时,该应用会发送多位置更新:

{
  "/votes/uid3": null,
  "voteCount": 2
}

然后删除他们的投票:

voteCount

这意味着应用需要显式读取function vote(auth) { ref.child('voteCount').once('value', function(voteCount) { var updates = {}; updates['votes/'+auth.uid] = true; updates.voteCount = voteCount.val() + 1; ref.update(updates); }); } 的当前值,其中包含:

.write

它本质上是一个多地点交易,但后来内置了应用代码和安全规则,而不是Firebase SDK和服务器本身。

安全规则做了一些事情:

  1. 确保voteCount只能上升或下降1
  2. 确保用户只能添加/删除自己的投票
  3. 确保计数增加伴随投票
  4. 确保计数减少伴随着“无投票”
  5. 确保投票附有计数增加
  6. 请注意,规则不会:

    • 确保“无投票”伴随计数减少(可以使用"votes": { "$uid": { ".write": "auth.uid == $uid", ".validate": "(!data.exists() && newData.val() == true && newData.parent().parent().child('voteCount').val() == data.parent().parent().child('voteCount').val() + 1 )" } }, "voteCount": { ".validate": "(newData.val() == data.val() + 1 && newData.parent().child('votes').child(auth.uid).val() == true && !data.parent().child('votes').child(auth.uid).exists() ) || (newData.val() == data.val() - 1 && !newData.parent().child('votes').child(auth.uid).exists() && data.parent().child('votes').child(auth.uid).val() == true )", ".write": "auth != null" } 规则完成)
    • 重试失败的投票/未投票(处理并发投票/取消投票)

    规则:

            url: 'save_edit/'+$id+'?back='+document.location,
    

    jsbin用一些代码来测试这个:http://jsbin.com/yaxexe/edit?js,console