Firebase规则仅允许在Android Studio中进行一次更新 [英] Firebase rule to only allow one update in android studio

查看:95
本文介绍了Firebase规则仅允许在Android Studio中进行一次更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm creating an android studio voting application. It is using recyclerview to render candidates information from the database. Once the voter clicks on a vote button, the candidate is added a vote on the firebase realtime database. I wanted to make sure that a voter can only vote once. Is there a firebase rule I can use or do I have to do it in code?

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!
            }
        });
    }

推荐答案

Firebase的安全规则无法在单个节点下的特定属性中强制使用唯一值.但是(与NoSQL数据库通常一样),您可以使用特定的数据模型来实现用例.

Firebase's security rules cannot enforce unique value in a specific property under a single node. But (as is often the case with NoSQL databases) you can use a specific data model to implement the use-case.

通常的解决方案是使用选民的UID作为密钥.

The usual solution for this is to use the UID of the voter as the key.

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

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

Since keys must be unique in a JSON object, this structure ensures by definition that each UID can only vote once.

这与保留候选人的总票数是分开的.为此,您可以使用安全规则,也可以使用云功能.

This is separate from keeping the total votes for a candidate. For that you can either use security rules, or Cloud Functions.

这样做在安全性方面很有吸引力,因为这意味着您不需要任何服务器端代码.但是规则可能会变得非常复杂.有关此示例,请参阅我对以下问题的回答: Firebase数据库快速入门处理计数安全吗?

Doing this is in security is appealing, since it means you won't need any server-side code. But the rules can become quite complex. For an example of this, see my answer to this question: Is the way the Firebase database quickstart handles counts secure?

更简单,并且如今越来越普遍的方法是使用Cloud Function来做到这一点.在我最近从事的项目中,我具有以下云功能:

The simpler, and these days more common, approach is to do this with a Cloud Function. From a recent project I worked on, I have this Cloud Function:

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;
  })
});

因此,这将对每个唯一值进行计票.然后,它可以确保用户无法通过以下方式更改其现有投票:

So this tallies the votes for each unique value. It then ensures that users can't change their existing vote with:

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

因此,用户只有在使用自己的UID(auth.uid变量已预先填充且不能被欺骗)并且还没有投票的情况下才可以投票.

So a user can only vote if they user their own UID (the auth.uid variable is prepopulated and can't be spoofed), and if they haven't voted yet.

这篇关于Firebase规则仅允许在Android Studio中进行一次更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆