登录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; } }