1. 程式人生 > >平臺登錄時,1分鐘內連續錯誤5次建議鎖定帳號5分鐘。

平臺登錄時,1分鐘內連續錯誤5次建議鎖定帳號5分鐘。

code rda tex cti ogg esc nat factor !=

登錄controller

package com.zx.znydweb.controller;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.zx.znyd.common.LoginLock;
import com.zx.znyd.common.SpringContextUtil;
import com.zx.znyd.dao.UserDao;
import com.zx.znyd.data.model.User;
import com.zx.znydweb.interceptor.CheckLoggin;

@Controller
public class LoginController {
    private static final Logger logger = LoggerFactory.getLogger(LoginController.class);
    public static final String LOGINUSER = "LOGINUSER";
    public static final String ERRORMsg = "LoginController_ERRORMsg";
    public static final String USERNAME = "userName";
    public static final String PASSWORD = "passWord";

    @Autowired
    LoginLock redisUtil;
    
    @ResponseBody
    @RequestMapping(value = "/", method = RequestMethod.POST)
    public Map<String, Object> login(String userName, String passWord, String piccode, HttpSession session,
            HttpServletRequest req) {
    	//經過濾器過濾後重新賦值
    	passWord = req.getParameter("passWord");
    	piccode = req.getParameter("piccode");
    	userName = req.getParameter("userName");
        logger.trace("=======login====,{},{},{}", userName, passWord, piccode);
        Map<String, Object> retMap = new HashMap<String, Object>();
        // 判斷該用戶是否被鎖
        boolean isLock = redisUtil.isLoginLock(userName);
        if(isLock) {
        	logger.info("用戶"+userName+"被鎖定,請在5分鐘之後重試:"+isLock);
        	retMap.put("returnCode", "999");
            retMap.put("returnMessage", "用戶"+userName+"被鎖定,請在5分鐘之後重試");
            return retMap;
        } 
        if (session.getAttribute(LOGINUSER) == null) {
            String sessionPicCode = (String) session.getAttribute(VerifyCodeController.verifyCode);
            if (!checkLogInData(userName, passWord, piccode, retMap)) {
                session.setAttribute(ERRORMsg, retMap.get("returnMessage"));
                session.setAttribute(USERNAME, userName);
                session.setAttribute(PASSWORD, passWord);
            } else if (!(sessionPicCode != null && sessionPicCode.equalsIgnoreCase(piccode))) {
                session.setAttribute(ERRORMsg, "驗證碼錯誤");
                session.setAttribute(USERNAME, userName);
                session.setAttribute(PASSWORD, passWord);
            } else {
                UserDao userDao = SpringContextUtil.getBean(UserDao.class);
                try {
                    User u = userDao.findOneByUsernameAndPass(userName, passWord);
                    if (u != null) {
                        if (UserDao.validstatus.equals(u.getStatus())) {
                            session.setAttribute(LOGINUSER, u);

                            session.setAttribute(ERRORMsg, "");
                            logger.info("User [{}] loggin success.", u.getUserName());
                        } else {
                            session.setAttribute(ERRORMsg, "用戶狀態已失效");
                            session.setAttribute(USERNAME, userName);
                        }

                    } else {
                        session.setAttribute(ERRORMsg, "用戶名或密碼錯誤");
                        session.setAttribute(USERNAME, userName);
                    }
                } catch (Exception e) {
                    session.setAttribute(ERRORMsg, "用戶名或密碼錯誤");
                    session.setAttribute(USERNAME, userName);
                }
            }
        }

        if (session.getAttribute(LOGINUSER) != null) {
        	// 某時間間隔內用戶輸入錯誤次數
        	Long retriesLockNum = redisUtil.getLoginRetriesLockNum(userName);
            if(retriesLockNum != null && retriesLockNum < 5 && retriesLockNum > 0) {
            	logger.info("登錄成功,刪除用戶"+userName+"重試失敗次數:"+retriesLockNum);
            	redisUtil.delLoginRetriesLock(userName);
            } else if(retriesLockNum >= 5){// 處理並發
            	logger.info("用戶"+userName+"重試失敗次數:"+retriesLockNum);
            	 isLock = redisUtil.isLoginLock(userName);
            	 logger.info("用戶"+userName+"被鎖定,請在5分鐘之後重試:"+isLock);
                 if(!isLock) {
                	 redisUtil.loginLock(userName, 60*5);
                 } 
                 retMap.put("returnCode", "999");
                 retMap.put("returnMessage", "用戶"+userName+"被鎖定,請在5分鐘之後重試");
                 return retMap;
            }
            // 用戶已登陸
            retMap.put("returnCode", "0");
            retMap.put("returnMessage", "登陸成功");
            return retMap;
        }
        
        // 某時間間隔內用戶輸入錯誤次數
        Long retriesLockNum = redisUtil.setloginRetriesLockNum(userName, 60);
        logger.info("用戶"+userName+"重試失敗次數:"+retriesLockNum);
        if(retriesLockNum != null && retriesLockNum >= 5) {
        	isLock = redisUtil.loginLock(userName, 60*5);
        	logger.info("用戶"+userName+"被鎖定,請在5分鐘之後重試:"+isLock);
        }
        if (!StringUtils.isEmpty((String) session.getAttribute(ERRORMsg))) {
            req.setAttribute("errorMsg", (String) session.getAttribute(ERRORMsg));
            req.setAttribute("userName", (String) session.getAttribute(USERNAME));
            req.setAttribute("passWord", (String) session.getAttribute(PASSWORD));
        } else {
            req.setAttribute("errorMsg", "");
            req.setAttribute("userName", "");
            req.setAttribute("passWord", "");
        }
        retMap.put("returnCode", "999");
        retMap.put("returnMessage", session.getAttribute(ERRORMsg).toString());
        return retMap;
    }

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String login(HttpSession session, HttpServletRequest req) {

        if (session.getAttribute(LOGINUSER) != null) {
            // 用戶已登陸
            return "main";
        }
        if (!StringUtils.isEmpty((String) session.getAttribute(ERRORMsg))) {
            req.setAttribute("errorMsg", (String) session.getAttribute(ERRORMsg));
            req.setAttribute("userName", (String) session.getAttribute(USERNAME));
            req.setAttribute("passWord", (String) session.getAttribute(PASSWORD));
        } else {
            req.setAttribute("errorMsg", "");
            req.setAttribute("userName", "");
            req.setAttribute("passWord", "");
        }
        session.setAttribute(ERRORMsg, "");
        return "index";
    }

    @CheckLoggin
    @RequestMapping(value = "/userLogout", method = RequestMethod.POST)
    @ResponseBody
    public Map userLogout(HttpSession session) {
        session.invalidate();
        Map reture = new HashMap();
        reture.put("returnCode", "0");
        reture.put("returnMessage", "成功");
        return reture;
    }

    /**
     * For 4A 單點登錄
     * 
     * @param userName
     * @param passWord
     * @param piccode
     * @param session
     * @param req
     * @return
     */
    @RequestMapping(value = "/SSOLogin")
    public String sSOLogin(HttpSession session, HttpServletRequest req) {
        Cookie[] cookies = req.getCookies();
        if (cookies != null) for (Cookie cookie : cookies) {
            if (cookie.getName().equals("info_inside")) {
                String[] valArray;
                try {
                    valArray = new String(Base64.decodeBase64(cookie.getValue())).split("\\|");
                    if (valArray.length != 4) {
                        session.setAttribute(ERRORMsg, "獲取統一登錄平臺參數錯誤!");
                    } else if (!valArray[2].equals(getTokenStr(valArray[0] + valArray[1]))) {
                        session.setAttribute(ERRORMsg, "未知來源請求!");
                    } else if (System.currentTimeMillis() - Long.parseLong(valArray[3]) > 3600 * 1000) {
                        session.setAttribute(ERRORMsg, "請求已超時,請重新登錄!");
                    } else {
                        logger.trace("=======login====,{},{},{}", valArray[0], valArray[1], valArray[2], valArray[3]);
                        if (session.getAttribute(LOGINUSER) == null) {
                            UserDao userDao = SpringContextUtil.getBean(UserDao.class);
                            try {
                                User u = userDao.findOneByUsername(valArray[0]);
                                if (u != null) {
                                    if (UserDao.validstatus.equals(u.getStatus())) {
                                        session.setAttribute(LOGINUSER, u);
                                        session.setAttribute(ERRORMsg, "");
                                        logger.info("User [{}] SSOLogin success.", u.getUserName());
                                    } else {
                                        session.setAttribute(ERRORMsg, "用戶狀態已失效");
                                    }
                                } else {
                                    session.setAttribute(ERRORMsg, "用戶名或密碼錯誤");
                                }
                            } catch (Exception e) {
                                session.setAttribute(ERRORMsg, "用戶名或密碼錯誤");
                            }
                        }
                    }
                } catch (Exception e1) {
                    logger.trace("=======獲取統一登錄平臺參數錯誤!====,{}", cookie.getValue());
                }
                break;
            }
        }
        return "redirect:/";
    }

    /**
     * 加密算法
     * 
     * @param i1
     * @return
     */
    private String getTokenStr(String i1) {
        String i2 = "";
        for (int i = 0; i < i1.length(); i++) {
            int c = (int) i1.charAt(i);
            if (c >= 48 && c <= 57) {
                c = c - 48;
                c = (c + 5) % 10;
                c = c + 48;
            } else if (c >= 97 && c <= 122) {
                c = c - 97;
                c = (c + 13) % 26;
                c = c + 97;
            }
            i2 = i2 + (char) c;
        }
        return i2;
    }

    private boolean checkLogInData(String userName, String passWord, String piccode, Map<String, Object> retMap) {
        // 用戶名校驗
        String regex = "^[a-zA-Z0-9_\\-]+$";
        if (!userName.matches(regex)) {
            retMap.put("returnMessage", "用戶名只能包含字母數字下劃線或橫杠");
            return false;
        }
        if (userName.length() > 20) {
            retMap.put("returnMessage", "用戶名長度不能大於20位");
            return false;
        }
        //密碼校驗
        if (!passWord.matches(regex)) {
            retMap.put("returnMessage", "用戶名或密碼錯誤");
            return false;
        }
        if (passWord.length() > 20) {
            retMap.put("returnMessage", "密碼長度不能大於20位");
            return false;
        }
        if (passWord.length() < 6) {
            retMap.put("returnMessage", "密碼長度不能小於6位");
            return false;
        }
        // 驗證碼校驗
        String regex2 = "^[a-zA-Z0-9]+$";
        if (!piccode.matches(regex2)) {
            retMap.put("returnMessage", "驗證碼只能包含字母或數字");
            return false;
        }
        if (piccode.length() != 4) {
            retMap.put("returnMessage", "驗證碼長度必須是4位");
            return false;
        }
        retMap.put("returnMessage", "");
        return true;

    }

}

 工具類

package com.zx.znyd.common;

import java.io.Serializable;
import java.util.Date;
import java.util.Map;

import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import redis.clients.jedis.Jedis;

import com.cmos.core.logger.util.StringUtils;


/**
 * @Description: 登錄鎖定(*分鐘失敗*次,鎖定*分鐘)
 * @author 弓振
 * @date 2018年2月26日
 */
@Component
public class LoginLock {
	@Autowired
	@Qualifier("redisTemplate1")
	private RedisTemplate<Serializable, Object> redisTemplate1;
	/**
	 * 登錄次數驗證
	 * @param key
	 * @param retriesLifecycleTime 多長時間內重試有效(秒)
	 */
	public Long setloginRetriesLockNum(String key, int retriesLifecycleTime) {
		 String retriesLockscript = "local errorNum = redis.call(‘get‘,KEYS[1]) "
		 		+ "if errorNum == false "
		 			+ "then errorNum = redis.call(‘incr‘,KEYS[1]) redis.call(‘expire‘,KEYS[1],tonumber(ARGV[1])) return errorNum "
		 		+ "else return redis.call(‘incr‘,KEYS[1]) end";
		Long retriesLockNum = executeScript(retriesLockscript, 1, key, String.valueOf(retriesLifecycleTime));
		return retriesLockNum;
	}
	
	/**
	 * 登錄次數多,鎖定
	 * @param key
	 * @param retriesLifecycleTime 多長時間內重試有效(秒)
	 * @param retriesNum 重試次數
	 * @param lockTime 鎖定時間(秒)
	 * @return 鎖定true,否則false
	 */
	public boolean loginLock(String key,int lockTime) {
		String lockKey = key+"_lock";
		String lockScript = "if redis.call(‘setnx‘,KEYS[1],ARGV[1]) == 1 "
				+ "then redis.call(‘expire‘,KEYS[1],tonumber(ARGV[2])) return 1 "
				+ "else return 2 end";
		String nowTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:dd:ss");
		Long isLocked = executeScript(lockScript, 1, lockKey, nowTime, String.valueOf(lockTime));
		return isLocked != null && isLocked==1 ? true : false;		
	}
	
	/**
	 * 刪除重置lock
	 * @param key 
	 * @return
	 */
	public boolean delLoginRetriesLock(String key) {
		if(redisTemplate1.hasKey(key)) {
			redisTemplate1.delete(key);
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 得到失敗次數
	 * @param key
	 * @return
	 */
	public Long getLoginRetriesLockNum(String key) {
		String retriesLockscript = "return redis.call(‘get‘,KEYS[1]) ";
		String errorNum = executeScript(retriesLockscript, 1, key);
		return StringUtils.isBlank(errorNum) ? 0L : Long.parseLong(errorNum);
	}
	
	/**
	 * 是否鎖定
	 * @param key
	 * @return 鎖定 true,否則false
	 */
	public boolean isLoginLock(String key) {
		String lockKey = key+"_lock";
		String lockScript = "return redis.call(‘get‘,KEYS[1]) ";
		String lockVlaue = executeScript(lockScript, 1, lockKey);
		return StringUtils.isBlank(lockVlaue) ? false : true;
	}
	
	private <T> T executeScript(final String script, final int keyCount, final String... values) {
		T value = redisTemplate1.execute(new RedisCallback<T>(){
			@SuppressWarnings("unchecked")
			@Override
			public T doInRedis(RedisConnection connection)
					throws DataAccessException {
				Jedis jedis = (Jedis) connection.getNativeConnection();
				return (T) jedis.eval(script, keyCount, values);
			}
		});
		return value;
	}
}

  

平臺登錄時,1分鐘內連續錯誤5次建議鎖定帳號5分鐘。