2016-02-18 98 views
0

我想實現一個安全的投票系統,不能用客戶端控制檯中的Meteor.call()進行更改。如果他們登錄,每個人都可以上傳和下載一些帖子,但每個用戶和帖子只需要一次。製作投票系統安全Meteor.Methods

ONY我的客戶端Ive得到了這樣的事情:

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.有沒有辦法以一種安全的方式做到這一點?

回答

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

more on this technique

現在,讓我們把你的第一種方法:

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 } 
     }); 
     } 
    } 
    }, 
+0

嘿米歇爾!我嘗試了你的建議,如果我使用'userId = Meteor.userId();'爲什麼它沒有與'var userId = this.userId();'合作?感謝您的幫助! – decisionMaker

+0

如果我嘗試爲我的第二個調用'argumentVoteYesElse'實現相同的邏輯,我得到一個'無法調用方法'indexOf'未定義的錯誤。猜猜它的原因,我沒有插入votedUp時創建一個新的職位??。當有人點擊新帖子的第一次,並希望投票發佈此帖時,錯誤消息發生。所以在嘗試post.votedUp.indexOf(userId)時沒有voteedUp。我現在該做什麼?我已經爲帖子添加了投票向下按鈕。如果在voteDown上單擊第一次,然後更改爲voteUp,則會出現同樣的問題。 – decisionMaker

+0

查看對代碼的更改 –

1

您需要檢查用戶是否在服務器上的投票上/下陣列中。你有正確的客戶端邏輯,所以只需在服務器上進行實際更新之前應用相同的邏輯即可。

+0

肯定的,但我不知道如何獲得Meteor.userId()的數組值?像db.arguments.find({_ id:currentArgumentId ......?});我必須檢查數組,如果Meteor.userId();已經存在但我如何獲得值?我試過類似'var votedUpMeteorUser = Arguments.findOne(currentArgumentId); (Meteor.userId()!= null && votedUpMeteorUser.votedUp!= Meteor.userId())'{.....}但這不起作用 – decisionMaker

+1

您應該在服務器上使用this.userId。 –

0

我以前想過同樣的事情,我發現解決方案只是使用數組您不從客戶端傳遞的userId(您只保存當前用戶的ID)並計算數組中的總ID。它不會添加兩次相同的ID。

從我的代碼(你可以做其餘檢查一樣,如果用戶是disliker陣中,做一些事情等):

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 
}