登录失败(账号密码<5次时不提示),>=5次时,锁定时间5min,最高密码错误次数为10,第十次密码输入错误后,提醒,"账号已停用,请联系管理员开通",次日0时,重新计算错误次数
代码实现
java
public static String LOGIN_FAIL_LOCK = "login:error:count:";
public static String LOGIN_FAIL_COUNT = "lock";
@GetMapping("login")
public void login(String userName, String password) {
RedisUtil redisUtil = new RedisUtil();
TyqUser tyqUser = this.selectUserFromMysql(userName);
// 判断当前账号是否被锁定
String errorMessage = this.judgeLock(userName);
if (StrUtil.isNotEmpty(errorMessage)) {
throw new BizException(errorMessage);
}
String loginFailLockKey = LOGIN_FAIL_LOCK + userName;
String loginFailCountKey = LOGIN_FAIL_COUNT + userName;
String msg = null;
if (!tyqUser.getPassword().equals(userName)) {
// 密码错误,进行封禁账号
msg = loginFailLockJudge(loginFailLockKey, loginFailCountKey, tyqUser.getId());
} else {
// 登录成功,清空对应的 锁定次数
redisUtil.delete(loginFailCountKey);
redisUtil.delete(loginFailLockKey);
}
}
// 模拟从数据库查询user
public TyqUser selectUserFromMysql(String userName){
return new TyqUser();
}
// 判断当前账号是否可以进行登录
public String judgeLock(String userName) {
RedisUtil redisUtil = new RedisUtil();
BizResponse<Object> bizResponse = null;
if (StrUtil.isEmpty(userName)) {
return null;
}
Map<String, Object> param = new HashMap<>();
TyqUser user = this.selectUserFromMysql(userName);
// 查询 user 的状态,是否停用,禁用
if ("停用".equals(user.getStatus())) {
return "账号已停用";
}
// 判断账号是否锁定,锁定就进行提示
String msg = null;
String loginFailLockKey = LOGIN_FAIL_LOCK + userName;
String loginFailCountKey = LOGIN_FAIL_COUNT + userName;
if (redisUtil.getObject(loginFailCountKey) != null) {
String loginFailCountValue = String.valueOf(redisUtil.getObject(loginFailCountKey));
if (Integer.parseInt(loginFailCountValue) > 4) {
if (redisUtil.getObject(loginFailLockKey) != null) {
Long ttlForLoginFailLock = redisUtil.ttl(loginFailLockKey);
if (ttlForLoginFailLock > 0) {
String minuteLeft = TimeUtil.getMinuteStringFromSeconds(ttlForLoginFailLock);
msg = "输入错误次数过多, 请" + minuteLeft + "后再试";
return msg;
}
}
}
}
return msg;
}
public int updateStatus(String id, String status) {
return 1;
}
// 登录失败次数校验
public String loginFailLockJudge(String loginFailLockKey, String loginFailCountKey, String id) {
RedisUtil redisUtil = new RedisUtil();
// 当前时间到次日零点的剩余时间
Long remainToZero = ChronoUnit.SECONDS.between(LocalDateTime.now(), LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withSecond(0));
// key
String loginFailCountValue = redisUtil.get(loginFailCountKey);
String msg = null;
Long maxTtl = 5 * 60L;
if (StrUtil.isNotEmpty(loginFailCountValue)) {
Integer loginFailCount = Integer.parseInt(loginFailCountValue);
loginFailCount ++;
// 前5次登录失败,提示错误信息
if (loginFailCount < 5) {
redisUtil.setObjectAndExpireSeconds(loginFailLockKey, loginFailCount, remainToZero);
redisUtil.setObjectAndExpireSeconds(loginFailCountKey, loginFailCount, remainToZero);
msg = "密码错误,请再次输入";
return msg;
}
if (loginFailCount < 10) {
Long ttl = maxTtl;
if(ttl > remainToZero) {
ttl = remainToZero;
}
redisUtil.setObjectAndExpireSeconds(loginFailLockKey, loginFailCount, ttl);
redisUtil.setObjectAndExpireSeconds(loginFailCountKey, loginFailCount, ttl);
String minuteLeft = TimeUtil.getMinuteStringFromSeconds(ttl);
msg = "密码错误次数频繁,请" + minuteLeft + "后再试";
} else {
// 修改mysql中的账号状态
this.updateStatus(id, "停用");
msg = "账号已停用";
}
} else {
// 第一次登录失败
redisUtil.setObjectAndExpireSeconds(loginFailLockKey, "1", remainToZero);
redisUtil.setObjectAndExpireSeconds(loginFailCountKey, "1", remainToZero);
msg = "密码错误,请再次输入";
}
return msg;
}