1、可配参数说明:
错误登录次数:用户可“连续”输入错误的次数;
登录错误间隔时间:第一次错误~最后一次错误的间隔时间(此处用分钟做计算);
封禁时间:登录错误次数达到上限后,禁止用户登录的时长(此处用分钟做计算);
2、表设计:
h_login_miss:记录登录次数和状态-主表
h_login_log:记录登录信息-附表-主要记录了每个用户的登录时间(排除“登录错误间隔时间”之前的错误登录记录),用于实现(登录错误间隔时间的可配化--如果需求是“每日错误登录限制”,此表可省略)
CREATE TABLE `h_login_miss` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`employee_id` bigint(19) NOT NULL COMMENT '用户id',
`miss_number` int(11) unsigned zerofill DEFAULT NULL COMMENT '登录失败次数(登录成功就清0 失败就+1)',
`miss_time` datetime DEFAULT NULL COMMENT '锁定登录时间:这个时间如果大于当前时间 则不能登录',
`miss_flag` char(1) DEFAULT NULL COMMENT '锁定标志:0未锁定状态 1代表锁定状态 ',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='登录错误限制表';
CREATE TABLE `h_login_log` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',`employee_id` bigint(19) NOT NULL COMMENT '用户id',
`flag` char(1) DEFAULT NULL COMMENT '登录状态(0:登录成功 1:登录失败)',
`ip_address` varchar(255) DEFAULT NULL COMMENT 'ip地址',
`login_time` datetime DEFAULT NULL COMMENT '登录时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=261 DEFAULT CHARSET=utf8 COMMENT='登录记录表';
3、代码:
此处只写出MVC层代码和核心业务代码;(--使用切面,在登录模块做验证)
@Aspect @Configuration public class LoginAspect extends BaseController{ private final Logger logger = Logger.getLogger(this.getClass()); // 定义切点Pointcut @Pointcut("execution(* com.credit.controller.shiro.LoginController.loginPost(String , String , String ,*)) && args(username,password,code,session)") public void excudeService(String username, String password, String code, HttpSession session) {} /** * * @Title:doAround * @Description: 环绕触发 */ @Around("excudeService(username, password, code,session)") public Object doAround(ProceedingJoinPoint pjp,String username, String password, String code, HttpSession session) throws Throwable { Boolean flag = true; Object resultStr = null; if (StringUtils.isBlank(username)) { return renderError("用户名不能为空"); } if (StringUtils.isBlank(password)) { return renderError("密码不能为空"); } //验证是否含可能登录 //此处调用的boot代码,可直接更改为,方法调用(具体方法在下面的代码中) String url = FileHelpper.map.get("url.userUrl")+ FileHelpper.map.get("loginMiss.judgeMiss"); StringBuffer str = new StringBuffer(); str.append("loginName=" + username); logger.info("请求参数:"+url+"?"+str); String result = HttpReqUtil.sendPost(url,str.toString()); logger.info("返回结果集:"+result); if (StringUtils.isBlank(result)){ return renderError("不存在该用户"); } JSONObject jsonObject = JSONObject.parseObject(result); Integer resultNo = jsonObject.getInteger("resultNo"); if (resultNo == 0) { resultStr = pjp.proceed();//登录目标方法 result的值就是被拦截方法的返回值 //获取request HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); //设置IP地址--登录成功后记录用户登录数据 String ipAddress = IPUtils.getIpAddr(request); String url2 = FileHelpper.map.get("url.userUrl")+ FileHelpper.map.get("loginMiss.importMiss"); StringBuffer str2 = new StringBuffer(); str2.append("loginName=" + username); str2.append("&flag=" + (((Result)resultStr).getResultNo()==0)); str2.append("&ipAddress=" + ipAddress); logger.info("请求参数:"+url2+"?"+str2); String result2 = HttpReqUtil.sendPost(url2,str2.toString()); logger.info("返回结果集:"+result2); return resultStr; }else { return renderError("不存在该用户"); } } }
/** * 登录错误或正确处理 * @param employeeId * @param flag true正确 false用户输入错误 * @return */ @Override public int importMiss(Long employeeId,Boolean flag) { LoginMiss login = loginMissMapper.findLoginByEmployeeId(employeeId); if (login == null) { if (flag) { addLoginMiss(employeeId, 0); } else { addLoginMiss(employeeId, 1); } } if (flag) { login.setMissFlag("0"); login.setMissNumber(0); login.setMissTime(new Date()); } else { if (DateHelper.compareDate(login.getMissTime(),new Date())==1){ return 1; }
//注:此处是获取3个可配参数 String missNum = enumValueMapper.getValue(Integer.valueOf(FileHelpper.map.get("enumValue.missNum")));//错误登陆限制次数 String intervalTime = enumValueMapper.getValue(Integer.valueOf(FileHelpper.map.get("enumValue.intervalTime")));//错误登陆间隔(单位:分钟) String forbidTime = enumValueMapper.getValue(Integer.valueOf(FileHelpper.map.get("enumValue.forbidTime")));//错误登陆禁止时间(单位:分钟) //排除超过禁止时间的错误登陆信息 List<LoginLog> logs = loginLogMapper.findMissLog(employeeId, login.getMissNumber()); for (int i = 0; i < logs.size(); i++) { LoginLog log = logs.get(i); if (DateHelper.getDaysbytwoDate2(new Date(), log.getLoginTime()) > Integer.valueOf(intervalTime)) { logs.remove(i); } } login.setMissNumber(logs.size());//设置错误次数 if (login.getMissNumber() + 1 > Integer.valueOf(missNum)) {//需要禁止登录 login.setMissFlag("1"); try { login.setMissTime(DateHelper.addDate(new Date(), Long.valueOf(forbidTime)));//加上对应的禁止时间 } catch (ParseException e) { e.printStackTrace(); } } else { login.setMissNumber(login.getMissNumber() + 1); login.setMissFlag("0"); login.setMissTime(new Date()); } } return loginMissMapper.updateByPrimaryKeySelective(login); } /** * 判断是否在锁定时间 即:是否可以登录 */ @Override public String judgeMiss(Long employeeId) { LoginMiss login = loginMissMapper.findLoginByEmployeeId(employeeId); if (login == null) { addLoginMiss(employeeId, 0); } if (DateHelper.compareDate(new Date(),login.getMissTime())==1){ return null; }else {//不可以登录 return DateHelper.dateFormat1(login.getMissTime()); } }