java 实现登录输入密码错误3次 锁定5分钟

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的区别和联系

  1. ServletContext:范围最大,应用程序级别的,整个应用程序都能访问;
  2. HttpSession:会话级别的,在当前的浏览器中都能訪问[不论是在同一浏览器开多少窗体,都能够访问],可是换个浏览器就不行了,就必须又一次创建session;
  3. 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);
	}
  • 8
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值