1.测试效果
先贴测试效果
2.登录接口
只需要注意HttpSession 这个入参, checkLock, addFailNum, cleanFailNum 这几个方法, 其他的都是业务代码, 可以无视
如果需要改超时时间, 修改timeDifference 参数旁边的数值即可, 如果数值需指定可以抽取出来
@RequestMapping(value = "/login")public Result<?> login(@RequestBody String body, HttpServletResponse response, HttpSession session) throws Exception {JsonNode jsonNode = objectMapper.readTree(body);String phoneNo = jsonNode.get("phoneNo").asText();Employee employee = employeeService.selectByPhoneNo(jsonNode.get("phoneNo").asLong());if (employee == null) {return Result.ERROR("用户不存在!");}//效验账号是否锁定if(!checkLock(session, phoneNo)) {return Result.ERROR("该账号已被锁定5分钟!");}if (!jsonNode.get("password").asText().equalsIgnoreCase(employee.getPassword())) {//插入错误记录addFailNum(session, phoneNo);return Result.ERROR("密码错误!");}if (1 != employee.getStatus()){return Result.ERROR("账号被禁用!");}List<Integer> deptIdList = new ArrayList<>deptIdList.add(employee.getDepartmentId());Cookie cookie = new Cookie("Access-Token", JwtUtils.createJWT(EmployeeInfo.builder().id(employee.getId()).name(employee.getName()).phoneNo(jsonNode.get("phoneNo").asLong()).deptList(deptIdList).timestamp(System.currentTimeMillis()).build()));cookie.setPath("/auth");cookie.setMaxAge(3600 * 8);cookie.setHttpOnly(true);response.addCookie(cookie);response.setContentType("application/json;charset=utf-8");//前端参数Map<String,Object> result = new HashMap<>();//查询员工项目首页List<CompanyProject> companyProjects = employeeService.selectProjectHomeByEmployeeId(employee.getId());if (companyProjects != null){List<String> homeUrls = new ArrayList<>();for (CompanyProject companyProject : companyProjects) {String url = companyProject.getHomeUrl() + "?token=" + cookie.getValue();homeUrls.add(url);}result.put("projectHome", JSONArray.parseArray(JSON.toJSONString(homeUrls)));}//登录成功,清空登录失败记录cleanFailNum(session, phoneNo);result.put("id",employee.getId());result.put("name",employee.getName());result.put("username",employee.getUsername());result.put("password",employee.getPassword());result.put("avatar",employee.getAvatar());result.put("status",employee.getStatus());result.put("telephone",employee.getPhoneNo());result.put("createTime",new Date().getTime());result.put("deleted",0);result.put("lang","zh-CN");result.put("token", cookie.getValue());result.put("responseCode", "10000");return Result.OK(result);}
3.方法代码
注意:
这种方式是使用HttpSession实现的, 生命周期范围是会话级别的, 关闭浏览器换了一个, 用户就又可以输入密码了, 锁定不会计时, 如果需要更大的范围, 可以使用ServletContext
ServletContext、HttpSession和HttpServletRequest的区别和联系
ServletContext:范围最大,应用程序级别的,整个应用程序都能访问;HttpSession:会话级别的,在当前的浏览器中都能訪问[不论是在同一浏览器开多少窗体,都能够访问],可是换个浏览器就不行了,就必须又一次创建session;HttpServletRequest:范围最小,请求级别,请求结束,变量的作用域也结束【也就是仅仅是一次访问,访问结束,这个也结束】。
/*** 校验用户登录失败次数* @param session* @param phoneNo* @return*/private boolean checkLock(HttpSession session, String phoneNo) {Object obj = session.getServletContext().getAttribute(phoneNo);if (obj == null) {return true;}JSONObject json = JSON.parseObject(JSON.toJSONString(obj));Integer num = json.getInteger("num");Date date = json.getDate("lastDate");long timeDifference = ((new Date().getTime() - date.getTime()) / 60 / 1000);return num < 3 || timeDifference >= 5;//修改这个数值,可以调整超时时间}/*** 新增用户登录失败次数* @param session* @param phoneNo*/private void addFailNum(HttpSession session, String phoneNo) {Object obj = session.getServletContext().getAttribute(phoneNo);JSONObject json;int num = 0;if (obj == null) {json = new JSONObject();} else {json = JSON.parseObject(JSON.toJSONString(obj));num = json.getInteger("num");Date date = json.getDate("lastDate");long timeDifference = ((new Date().getTime() - date.getTime()) / 60 / 1000);if (timeDifference >= 5) {num = 0;}}json.put("num", num + 1);json.put("lastDate", new Date());session.getServletContext().setAttribute(phoneNo, json);}/*** 清理用户登录失败的记录* @param session* @param phoneNo*/private void cleanFailNum(HttpSession session, String phoneNo) {session.getServletContext().removeAttribute(phoneNo);}
4.ServletContext的方式实现
这种方式实现的,是应用程序级别的,只要程序没停止运行,计时就存在。
复制改一下,可用。
@RequestMapping(value = "/login")public Result<?> login(@RequestBody String body, HttpServletRequest request, HttpServletResponse response) throws Exception {JsonNode jsonNode = objectMapper.readTree(body);ServletContext servletContext = request.getServletContext();String phoneNo = jsonNode.get("phoneNo").asText();Employee employee = employeeService.selectByPhoneNo(jsonNode.get("phoneNo").asLong());if (employee == null) {return Result.ERROR("用户不存在!");}//效验账号是否锁定if(!checkLock(servletContext, phoneNo)) {return Result.ERROR("该账号已被锁定5分钟!");}if (!jsonNode.get("password").asText().equalsIgnoreCase(employee.getPassword())) {//插入错误记录addFailNum(servletContext, phoneNo);return Result.ERROR("密码错误!");}if (1 != employee.getStatus()){return Result.ERROR("账号被禁用!");}//登录成功,清空登录失败记录cleanFailNum(servletContext, phoneNo);return Result.OK(result);}
/*** 校验用户登录失败次数* @param servletContext* @param phoneNo* @return*/private boolean checkLock(ServletContext servletContext, String phoneNo) {Object obj = servletContext.getAttribute(phoneNo);if (obj == null) {return true;}JSONObject json = JSON.parseObject(JSON.toJSONString(obj));Integer num = json.getInteger("num");Date date = json.getDate("lastDate");long timeDifference = ((new Date().getTime() - date.getTime()) / 60 / 1000);return num < 3 || timeDifference >= 5;}/*** 新增用户登录失败次数* @param servletContext* @param phoneNo*/private void addFailNum(ServletContext servletContext, String phoneNo) {Object obj = servletContext.getAttribute(phoneNo);JSONObject json;int num = 0;if (obj == null) {json = new JSONObject();} else {json = JSON.parseObject(JSON.toJSONString(obj));num = json.getInteger("num");Date date = json.getDate("lastDate");long timeDifference = ((new Date().getTime() - date.getTime()) / 60 / 1000);if (timeDifference >= 5) {num = 0;}}json.put("num", num + 1);json.put("lastDate", new Date());servletContext.setAttribute(phoneNo, json);}/*** 清理用户登录失败的记录* @param servletContext* @param phoneNo*/private void cleanFailNum(ServletContext servletContext, String phoneNo) {servletContext.removeAttribute(phoneNo);}