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);
}