我正在尝试实施一个安全的投票系统,并且无法通过客户端控制台中的Meteor.call()进行更改。如果他们登录,每个人都可以上下调整一些帖子。但每个用户和帖子只需一次。
Ony我的客户端我有这样的事情:
Template.postArgument.events({
'click .yes':function() {
if(Meteor.user()) {
var postId = Arguments.findOne({_id:this._id})
var currentArgumentId = this._id;
if($.inArray(Meteor.userId(), postId.votedUp) ===-1) {
if($.inArray(Meteor.userId(), postId.votedDown) !==-1) {
Meteor.call('argumentVoteYes',currentArgumentId);
} else {
Meteor.call('argumentVoteYesElse',currentArgumentId);
}
} else {
Meteor.call('argumentVoteYesElseElse',currentArgumentId);
}
}
}}
)};
在我的服务器上:
Meteor.methods({
'argumentVoteYes':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$pull: {votedDown: Meteor.userId()},
$inc: {score: 2 },
$addToSet: {votedUp: Meteor.userId() }
});
},
'argumentVoteYesElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: 1 },
$addToSet: {votedUp: Meteor.userId() }
});
},
'argumentVoteYesElseElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: -1 },
$pull: {votedUp: Meteor.userId()}
});
}
'argumentVoteNo':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$pull: {votedUp: Meteor.userId()},
$inc: {score: -2 },
$addToSet: {votedDown: Meteor.userId() },
});
},
'argumentVoteNoElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: -1 },
$addToSet: {votedDown: Meteor.userId() },
});
},
'argumentVoteNoElseElse':function(currentArgumentId){
Arguments.update(currentArgumentId, {
$inc: {score: 1 },
$pull: {votedDown: Meteor.userId()}
});
},
});
问题是我如何获得这种安全性,例如,如果有人呼叫Meteor.call('argumentvoteYes', "someID" , {$inc: {score:2}});
它将增加2分。如果用户两次调用,则投票将增加4.有没有办法做到这一点安全的方式?
答案 0 :(得分:1)
您需要检查用户是否在服务器上的votedUp / down数组中。您拥有逻辑权限客户端,因此在服务器上进行实际更新之前,只需应用相同的逻辑。
答案 1 :(得分:1)
您不必担心方法会有额外的增量,因为您的方法只接受单个参数。但是你确实需要防范其他黑客攻击:
让我们首先扩展Match
对象,以便我们检查_id
是否只是:
Match._id = Match.Where(function(id){
check(id, String); // first make sure we're dealing with a string
// then grep for an exactly 17 character alphanumeric string
return /^[a-zA-Z0-9]{17,17}/.test(id);
});
现在让我们采取你的第一种方法:
Meteor.methods({
'argumentVoteYes':function(currentArgumentId){
check(currentArgumentId,Match._id); // will error if not an _id
var post = Arguments.findOne({ _id: currentArgumentId });
var userId = Meteor.userId(); // the current user
if ( post && userId ){ // make sure a real user is operating on an actual document
// only update if no votes have been recorded OR
// user hasn't already voted
if ( !post.votedUp || post.votedUp.indexOf(userId) === -1 ){
Arguments.update(currentArgumentId, {
$pull: { votedDown: userId },
$inc: { score: 2 },
$addToSet: {votedUp: userId }
});
}
}
},
答案 2 :(得分:0)
之前我曾经想过同样的事情,我发现解决方案只是使用了一组userId,你不会从客户端传递(你只需保存当前用户的ID)并计算数组中的总ID。它没有两次添加相同的ID。
从我的代码中(您可以执行其余的检查,例如,如果用户处于不喜欢的数组中,请执行某些操作等)。
likeActivity: function (activityId) {
Activities.update(activityId,{
$addToSet: {
likers: this.userId,
}
});
},
unlikeActivity: function (activityId) {
Activities.update(activityId,{
$pull: {
likers: this.userId,
}
})
}
在我的帮手中:
likeCount: function() {
return this.likers.length
}