【java登录锁定功能】redis实现登录失败锁定账号

发布于:2024-07-14 ⋅ 阅读:(146) ⋅ 点赞:(0)

登录失败(账号密码<5次时不提示),>=5次时,锁定时间5min,最高密码错误次数为10,第十次密码输入错误后,提醒,“账号已停用,请联系管理员开通”,次日0时,重新计算错误次数

代码实现



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