Firebase规则仅允许在Android Studio中进行一次更新 [英] Firebase rule to only allow one update in 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屋!