【问题标题】:How to create a secure like counter in Firebase Realtime Database创建类似计数器 Firebase 数据库的最佳实践
【发布时间】:2022-11-09 22:51:11
【问题描述】:

我的数据库中有一个用户节点,用于存储有关用户的任何信息。然后在我的应用程序中,我必须图像按钮:

mlike = root.findViewById(R.id.btn_like);
mdislike = root.findViewById(R.id.btn_dislike);
mlike.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
           likeStations();
        }
    });

 mdislike.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
           dislikeStations();
        }
    });

private void dislikeStations(){

 db = FirebaseDatabase.getInstance();
    ref = db.getReference().child("Users").child(user);

    DatabaseReference likesRef = FirebaseDatabase.getInstance().getReference().child("STATIONS").child(station);
    likesRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

            if (dataSnapshot.exists()) { 
Boolean dislike_snapshot = dataSnapshot.child("downvote").getValue(Boolean.class);
likeref.child("downvote").setValue(+1)

            }
}

然后对于 likeStations() 方法来说几乎是一样的。我想知道的是如何确保他们只能单击一次按钮,或者如果他们在单击不喜欢后单击喜欢它会在将 1 放在喜欢之前从不喜欢中删除 1。

我知道它将使用用户节点,因此我将它添加到问题中。

【问题讨论】:

  • 没有最佳实践,只有上下文中的良好实践。
  • 抱歉,我的问题不符合标准@EJoshuaS-StandwithUkraine,我以最好的方式询问:)

标签: java android firebase firebase-realtime-database


【解决方案1】:

它总是从拥有正确的数据结构开始。如果您希望用户只被允许执行一次操作,您需要:

  1. 为了能够识别用户,请使用/到Firebase Authentication 登录。
  2. 一种允许检查他们之前是否采取过操作的数据结构。这通常是以 UID 作为键的映射,因为这是确保唯一性的唯一方法。

    由于您想分别跟踪赞成票和反对票,那就是:

    upvotes: {
      "uid1": true,
      "uid2": true
    },
    downvotes: {
      "uid3": true
    }
    

    现在,您的其余要求是有关此结构的一堆安全规则。


    例如,允许用户为自己投票,看起来像这样:

    {
      "rules": {
        ...
        "upvotes": {
          "$uid": {
            ".write": "auth.uid === $uid"
          }
        },
        "downvotes": {
          "$uid": {
            ".write": "auth.uid === $uid"
          }
        }
      }
    }
    

    接下来,用户只能投票或者否决票,而不是两者,是这样的:

    "upvotes": {
      "$uid": {
        ".write": "auth.uid === $uid
                && !newData.parent().parent().child('downvotes').child(auth.uid).exists()"
      }
    },
    

    然后当然还有downvotes 下的等效规则。


    通过上述规则,用户可以投赞成票使用这个 JSON 补丁(您可以在 Android 中将其构建为 Map):

    {
      "upvotes/uid1": true
    }
    

    反对票将是:

    {
      "downvotes/uid1": true
    }
    

    但是,如果他们已经投了赞成票,那将被拒绝,因此您可以通过执行以下(单个)写入操作将他们的赞成票切换为反对票:

    {
      "upvotes/uid1": null,
      "downvotes/uid1": true
    }
    

    这里的null 删除了他们的赞成票,true 写入了反对票,两者都是作为单个操作发生的。


    存储和保护计数器

    最后,这让我们了解了您所询问的计数,这是与唯一性不同的主题。现在存储计数是可选的,因为信息已经存在于 UID 的数量中。但这是一个很好的优化,因为没有存储计数器,用户必须下载所有 UID 值来计算它们。

    于是数据结构变为:

    upvotes: {
      "uid1": true,
      "uid2": true
    },
    upvoteCount: 2,
    downvotes: {
      "uid3": true
    },
    downvoteCount: 1
    

    既然您已经有了数据结构并且我们已经看到了转换,那么确保计数的变化与正在投的票相匹配就变成了一个问题。

    第一个例子是我们在上面看到的upvote sn-p:您可以在投赞成票时增加赞成票数.在规则中

    "upvoteCount": {
      ".write": "(
                  newData.val() = data.val() + 1
                  newData.parent().parent().child('upvotes').child(auth.uid).exists()
                 && !data.parent().parent().child('upvotes').child(auth.uid).exists()
                )"
    }
    

    如果您阅读上面的定义,我希望这个表达式是有意义的:

    1. 用户只能将upvote计数增加1,
    2. 且仅当他们将其 UID 添加到 upvotes 列表中时,
    3. 如果它以前不存在

      如果他们取消投票,您同样需要处理减少赞成票数,然后还要处理反对票数。这些规则都是相似的,但又是分开的。

      一旦你有了它,最后一步是增强upvotesdownvotes 的规则,以要求用户在投票时更新计数。当用户投票时,他们还必须更新计数.所以这与我们刚刚看到的规则相反:

      "upvotes": {
        "$uid": {
          ".write": "auth.uid === $uid
                  && newData.exists() 
                  && !data.exists()
                  &&  newData.parent().parent().child('upvoteCount').val() == 
                         data.parent().parent().child('upvoteCount').val() + 1
        }
      },
      

【讨论】:

  • 他们使用身份验证@frank 登录。我还需要一个计数器还是可以使用getChildren计算uid?
  • 计数器永远不会需要,但没有它,每个客户端都必须下载所有 UID 以确定它们的数量。我仍在研究答案,并将其扩展以展示如何保护柜台。这绝对(甚至)比“仅仅”独特的投票更复杂,所以我可以理解如果你离开柜台直到数据变得太大。
  • 哇,这不是我所期待的,哈哈。我会仔细阅读您发布的这些信息,然后回复您,谢谢@frank
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-17
  • 1970-01-01
  • 1970-01-01
  • 2012-05-24
  • 2018-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多