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

登录失败(账号密码<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;
    }
相关推荐
liangshanbo121519 分钟前
虚拟列表深度面试题整理
java·开发语言·前端
ZISHU_98723 分钟前
用 TLabel 给 SynTouch BioTac 数据做语义标注:从原始信号到结构化标注
开发语言·人工智能·python·数据·机器人触觉
gugucoding30 分钟前
59. 【Java】Spring Boot 入门:第一个 Web 应用
java·开发语言·spring boot
m0_617493941 小时前
SSLError [ASN1: NOT_ENOUGH_DATA] 问题排查与解决指南
python·ssl
whcyhhh1 小时前
头歌实践教学平台:数据科学与大数据技术导论(七上)
大数据·数据库·python
10mAh1 小时前
【Java】HashMap 的 put 到底做了什么?——冲突、扩容与树化实测
java·开发语言·hash
我命由我123452 小时前
人脸识别 - 勒克斯(光线照射到物体表面上的明亮程度)
android·java·学习·java-ee·人脸识别·学习方法·android runtime
ServBay2 小时前
AI 工程师必备的 9 个 Python 库,从数据验证到模型优化
后端·python·ai编程
TechLee2 小时前
跨语言加解密总对不上?这个纯 Go 神库让 AES/RSA 与 PHP、Java 100% 互通
java·后端·算法