使投票系统安全Meteor.方法
我正在尝试实现一个安全的投票系统,它不能通过客户端控制台的Meteor.call()进行更改。每个人都可以在登录后上下投票。但对于每个用户和帖子,每次只需一次 就我的客户而言,我得到了这样的东西:使投票系统安全Meteor.方法,meteor,meteor-methods,Meteor,Meteor Methods,我正在尝试实现一个安全的投票系统,它不能通过客户端控制台的Meteor.call()进行更改。每个人都可以在登录后上下投票。但对于每个用户和帖子,每次只需一次 就我的客户而言,我得到了这样的东西: Template.postArgument.events({ 'click .yes':function() { if(Meteor.user()) { var postId = Arguments.findOne({_id:this._id}) var
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。有什么方法可以安全地执行此操作吗?您需要检查用户是否位于服务器上的votedUp/down阵列中。您的逻辑位于客户端右侧,因此在服务器上执行实际更新之前,只需应用相同的逻辑。您需要检查用户是否位于服务器上的votedUp/down阵列中。您在客户端拥有逻辑,因此在服务器上执行实际更新之前,只需应用相同的逻辑。您不必担心方法中会出现额外的增量,因为您的方法只接受一个参数。但是,您确实需要防范其他黑客:
让我们首先扩展匹配
对象,以便检查\u 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 }
});
}
}
},
您不必担心方法会有额外的增量,因为您的方法只接受一个参数。但是,您确实需要防范其他黑客:
让我们首先扩展匹配
对象,以便检查\u 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 }
});
}
}
},
我以前也这么想过,我发现了一个解决方案,就是只使用一个用户ID数组,而不是从客户端传递(只保存当前用户的ID)并计算数组中的总ID。它不会两次添加相同的ID
从我的代码中(您可以执行其余的检查,如用户是否在Dislike数组中,是否执行某些操作等):
在我的助手中:
likeCount: function() {
return this.likers.length
}
我以前也这么想过,我发现了一个解决方案,就是只使用一个用户ID数组,而不是从客户端传递(只保存当前用户的ID)并计算数组中的总ID。它不会两次添加相同的ID
从我的代码中(您可以执行其余的检查,如用户是否在Dislike数组中,是否执行某些操作等):
在我的助手中:
likeCount: function() {
return this.likers.length
}
是的,但我不知道如何获取Meteor.userId()的数组值?类似于db.arguments.find({u id:currentArgumentId……?});我必须检查数组是否为Meteor.userId();已经存在,但如何获取值?我尝试了类似于var votedUpMeteorUser=Arguments.findOne(currentArgumentId)的方法;如果(Meteor.userId()!=null&&votedupmeteouser.votedUp!=Meteor.userId())
{….}但这不起作用,您应该在服务器上使用这个.userId。是的,但我不知道如何获取Meteor.userId()的数组值?类似于db.arguments.find({u id:currentArgumentId……?});我必须检查数组是否为Meteor.userId();已经存在,但如何获取值?我尝试了类似于var votedUpMeteorUser=Arguments.findOne(currentArgumentId)的方法;如果(Meteor.userId()!=null&&votedupmeteouser.votedUp!=Meteor.userId())
{….}但这不起作用,你应该在服务器上使用这个.userId。嘿,米歇尔!我尝试了你的建议,如果我使用userId=Meteor.userId(),它对我有效代码>为什么它不使用var userId=this.userId()代码>???谢谢你的帮助!如果我尝试为第二次调用argumentVoteYesElse
实现相同的逻辑,我将得到一个无法调用未定义的方法'indexOf'的错误。我猜这是因为我在创建新帖子时没有插入votedUp??。当有人第一次点击一篇新文章并想投票支持这篇文章时,会出现错误消息。因此,在尝试post.votedUp.indexOf(userId)时没有votedUp。我现在该怎么办??我现在已经为帖子添加了投票否决按钮。如果第一次点击voteDown,然后切换到voteUp,同样会出现问题。我想现在的问题在于我的逻辑。因为现在我可以在控制台中调用“voteUpYes”
。我的分数增加2,并且设置了votedUp:Meteor.userId()
。在此之后,我可以调用'voteyeselselse'
并减少计数器1,并且votedUp:Meteor.userId()
被删除。然后我可以再次调用“voteUpYes”
,以此类推。没有限制。。这个问题真的把我搞糊涂了=/除了注意到你需要对称性之外,我不确定我能帮你什么。嘿,米歇尔!我尝试了你的建议,如果我使用userId=Meteor.userId(),它对我有效代码>为什么它不使用var userId=this.userId()代码>???谢谢你的帮助!如果我尝试为第二次调用argumentVoteYesElse
实现相同的逻辑,我将得到一个无法调用未定义的方法'indexOf'的错误。我猜这是因为我在创建新帖子时没有插入votedUp??。当有人第一次点击一篇新文章并想投票支持这篇文章时,会出现错误消息。因此,在尝试post.votedUp.indexOf(userId)时没有votedUp。我现在该怎么办??我现在已经为帖子添加了投票否决按钮。如果第一次点击voteDown,然后切换到voteUp,同样会出现问题。我想现在的问题在于我的逻辑。因为现在我可以在控制台中调用“voteUpYes”
。我的分数增加2,并且设置了votedUp:Meteor.userId()
。在此之后,我可以调用'voteyeselselse'
并减少计数器1,并且votedUp:Meteor.userId()
被删除。然后我可以再次调用“voteUpYes”
,以此类推。没有限制。。这个问题真的把我搞糊涂了=/除此之外,我不确定我能帮你什么