【问题标题】:Firebase rule to only allow one update in android studioFirebase 规则仅允许在 android studio 中进行一次更新
【发布时间】:2020-07-07 12:23:48
【问题描述】:

我正在创建一个 android studio 投票应用程序。它使用 recyclerview 从数据库中呈现候选人信息。一旦选民点击投票按钮,候选人就会在 firebase 实时数据库中添加投票。 我想确保选民只能投票一次。我可以使用firebase规则还是必须在代码中使用它?

public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
        holder.name.setText(candidates.get(position).getFirstname());
        holder.party.setText(candidates.get(position).getParty());
        holder.category.setText(candidates.get(position).getCategory());
        Picasso.get().load(candidates.get(position).getImageurl()).into(holder.profilepic);

        holder.vote.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                updateTotalVotes("increaseTotalVotes", candidates.get(position).getImageurl());
            }
        });

    }

    public static void updateTotalVotes(final String operation, String key) {
        System.out.println("Inside updateTotalVotes");
        DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();

        DatabaseReference totalVotesRef = rootRef.child("candidates").child(key).child("totalVotes");
        totalVotesRef.runTransaction(new Transaction.Handler() {
            @Override
            public Transaction.Result doTransaction(MutableData mutableData) {
                System.out.println("Inside Transactions");
                Integer votes = mutableData.getValue(Integer.class);
                if (votes == null) {
                    System.out.println("Inside first if statement = null");
                    return Transaction.success(mutableData);
                }

                if (operation.equals("increaseTotalVotes")) {
                    System.out.println("Inside update Votes by adding 1");
                    mutableData.setValue(votes + 1);
                } else if (operation.equals("decreaseTotalVotes")){
                    mutableData.setValue(votes - 1);
                }

                return Transaction.success(mutableData);
            }

            @Override
            public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {
                // Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
            }
        });
    }

【问题讨论】:

    标签: android firebase firebase-realtime-database


    【解决方案1】:

    Firebase 的安全规则无法在单个节点下的特定属性中强制执行唯一值。但是(就像 NoSQL 数据库的情况一样)您可以使用特定的数据模型来实现用例。

    通常的解决方案是使用投票者的 UID 作为键。

    votes
      uid1: "candidate A"
      uid2: "candidate B"
      uid3: "candidate A"
    

    由于键必须在 JSON 对象中是唯一的,因此此结构根据定义确保每个 UID 只能投票一次。

    这与保留候选人的总票数是分开的。为此,您可以使用安全规则或 Cloud Functions。

    出于安全考虑,这样做很有吸引力,因为这意味着您不需要任何服务器端代码。但规则可能变得相当复杂。有关这方面的示例,请参阅我对这个问题的回答:Is the way the Firebase database quickstart handles counts secure?

    更简单且如今更常见的方法是使用云函数来执行此操作。从我最近参与的一个项目中,我有这个云函数:

    exports.countVote = functions.database.ref('/votes/{uid}').onCreate((snapshot, context) => {
      let value = snapshot.val();
      let countRef = snapshot.ref.parent.parent.parent.child(`totals/${value}`);
      return countRef.transaction(function(current) {
        return (current || 0) + 1;
      })
    });
    

    所以这会统计每个唯一值的投票。然后,它确保用户无法更改他们现有的投票:

    {
      "rules": {
        "votes": {
          "$uid": {
            ".write": "auth.uid === $uid && !data.exists()"
          }
        }
      }
    }
    

    因此,用户只有在使用自己的 UID(auth.uid 变量已预先填充且无法被欺骗)且尚未投票时才能投票。

    【讨论】:

    • 弗兰克我试过你的解决方案。我已经安装了 firebase 工具,然后运行 ​​firebase init 和 firebase deploy。在函数 index.js 里面,我放了你的云函数代码 sn-p。部署后,它反映在我的 firebase 仪表板上。然后我去了我的实时数据库,在规则下,我输入了你建议的规则代码 sn-p。我不确定它应该如何工作,因为我是云功能的新手,但是当我点击我的投票按钮时,它仍然会继续投票。我需要在您的代码 sn-p 上更改变量名称吗?
    • 您可能必须根据您的数据库结构和用例调整我的回答中的代码。我主要包括 Cloud Function 代码作为您可以做什么的示例。更重要的部分是您需要按照我也描述的方式更改数据结构。
    【解决方案2】:

    简短的回答是不,你不能按照 db 的规则。

    但是你可以在身份验证的帮助下做到这一点,哪个用户可以在候选人的子树中创建一个帐户和他的投票记录。这样子树孩子的数量就是这个候选人的票数。

    注意:如果创建了假帐户,我的解决方案可能会被破坏,我的建议也使用电话身份验证,以确认该帐户不是假的。

    【讨论】:

    • 这将与@Frank van Puffelen 的答案几乎相同
    猜你喜欢
    • 2023-04-10
    • 1970-01-01
    • 2021-07-08
    • 1970-01-01
    • 2021-07-14
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 2018-06-02
    相关资源
    最近更新 更多