Redisベースの毎日のログイン失敗回数制限

3747 ワード

1.考え方
以下は私が以前書いたコードで、高同時シーンを考慮していません.高同時シーンの場合、redisのsetメソッドの上書き値の問題を考慮するには、getの代わりにincrを使用し、setはデータの安全を保証します.
ログイン失敗回数をredisで記録し、ユーザーのusernameをkeyとする
ログインの要求を受け取るたびに、redisに行ってログイン回数が私たちが設定した制限回数以上であるかどうかを問い合せます.はい、直接戻ります.
2.コード
フロントログインとバックグラウンドクエリーデータベースのコード省略
2.1 controller
私がここで使っているJbootは、redisTemplateを取得する方法がJboot.me().getRedis()で、springならjedisTemplateでいいです.

//                     ,24      
 //           ,   10 
 final int limit = 3;
 JbootRedis jr = Jboot.me().getRedis();
 //Constants.LOGIN_COUNT = "LOGIN_COUNT"
 //account       username
 String key = Constants.LOGIN_COUNT + "_" + account;
 Integer count = jr.get(key);
 if(count == null){
   count = 0;
 }else {
   if (count >= limit) {
     //    
     ajaxJson.setMsg("                ,     。");
     ajaxJson.setSuccess(false);
     logger.error("   【"+account+"】             ");
     render(callback, gson.toJson(ajaxJson));
     return;
   }
 }
//...       username  user  
 if (user != null) {
   //  redis          
   Integer newCount = IncrFailLoginCount(key,count);
   logger.error("   【"+account+"】       ,"+ajaxJson.getMsg());
   ajaxJson.setMsg(ajaxJson.getMsg() + ",       :"+(limit-newCount));
   render(callback, gson.toJson(ajaxJson));
   return;
 }else{
   //     ,  redis    
   jr.del(key);
 }

2.2 IncrFailLoginCountメソッド

/**
 *             
 * @param key redis     
 * @param count          
 * @return count       
 */
private Integer IncrFailLoginCount(String key,Integer count) {
  JbootRedis jr = Jboot.me().getRedis();
  count++;
  //         23 59 59 
  long timeInMillis = DateUtils.getMillsecBeforeMoment(23, 59, 59, 999);
  if (timeInMillis < 100){
    //                          
    timeInMillis = 1000*60;
  }
  //       
  jr.set(key,count);
  //      ,  set pexpire
  jr.pexpire(key,timeInMillis);
  return count;
}

ここでは、時間を費やしたツールクラスです.具体的なコードは次のとおりです.

/**
*                 
* @param hour        
* @param min        
* @param sec       
* @param mill        
* @return
*/
public static long getMillsecBeforeMoment(int hour,int min,int sec,int mill){
  return getMillisecBetweenDate(new Date(),getMoment(hour,min,sec,mill));
}
/**
*             
 * @param before
 * @param after
 * @return
 */
public static long getMillisecBetweenDate(Date before, Date after){
 long beforeTime = before.getTime();
 long afterTime = after.getTime();
 return afterTime - beforeTime;
}
/**
*          Date
 * @param hour 24  
 * @param min   
 * @param sec  
 * @param mill   
 * @return
 */
public static Date getMoment(int hour,int min,int sec,int mill){
 Calendar calendar = Calendar.getInstance();
 calendar.setTime(new Date());
 calendar.set(Calendar.HOUR_OF_DAY,hour);
 calendar.set(Calendar.MINUTE,min);
 calendar.set(Calendar.SECOND,sec);
 calendar.set(Calendar.MILLISECOND,mill);
 return calendar.getTime();
}

3.まとめ
ここで注意すべき点は、redisが期限切れ時間を設定すると、再setは期限切れ効果をクリアし、再び永久状態になるため、毎回pexpire()redisにもう一つの方法が必要である:incr()は、この方法を呼び出すたびに、1つのキーの値を+1させ、このキーがなければ、初期は0再+1になる.カウンタを作るのに適していて、このケースでも使えますが、ここではログインに失敗したときにカウント+1して、ログイン前にcountを直接判断することを望んでいるだけなので、伝統的なget()、set()を使いました.興味のある学生は詳しく知ることができる.