springboot进行登录次数限制

10 篇文章 0 订阅

具体的可参考作者这篇文章:
后台添加登录次数限制
这里只做补充说明。


理想情况:
1、第一次登陆正确,直接进入。
2、第一次失败,第二次正确,直接进入。
3、失败次数达到之后,提示时间。等到时间到达之后,复现上面一二步。

显然,原来的并不满足需求,存在bug。具体的可自行验证。

以下是优化,前面内容可直接参考作者文章。

操作:

最后增加对时间的判断。

/**
     * 登录验证
     *
     * @param username 用户名
     * @param password 密码
     * @param code     验证码
     * @param uuid     唯一标识
     * @return 结果
     */
    public String login(String username, String password, String code, String uuid) {
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
            throw new CaptchaException();
        }
        // 用户验证
        Authentication authentication = null;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
//            authentication = authenticationManager
//                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
            authentication = authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(username, RsaUtils.decryptByPrivateKey(password)));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                //登录限制
                loginError(userService.selectUserByUserName(username));

                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new CustomException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUser());
        //判断时间
        judgeTime(userService.selectUserByUserName(username));
        // 生成token
        return tokenService.createToken(loginUser);
    }

对loginError方法的优化:

/**
     * 登陆错误限制
     * 更新时sys_user加两字段
     * error_nums int类型(默认0!!)
     * error_times varchar类型
     *
     * @param sysUser
     */
    public void loginError(SysUser sysUser) {
        long timeNow = timeToStampSecond(DateUtils.getTime());
//        if (StrUtil.isNotBlank(sysUser.getErrorTimes())) {
//            long errorTimes = timeToStampSecond(sysUser.getErrorTimes()) + UserStatus.WRONG_DURATION * 60;
//            if (errorTimes - timeNow <= 0) {
//                userService.cleanErrorNums(sysUser.getUserName());
//                sysUser.setErrorNums(0);
//            }else {
//
//            }
//        }
        //能进来代表用户正常 单纯密码错误
        if (sysUser.getErrorNums() > UserStatus.WRONG_TIMES) {
            long errorTimes = timeToStampSecond(sysUser.getErrorTimes()) + UserStatus.WRONG_DURATION * 60;
            if (errorTimes - timeNow > 0) {
                String s = formatHMS(errorTimes - timeNow);
                throw new CustomException("对不起,您的账号:" + sysUser.getUserName() + " 错误次数过多,请" + s + "后重试");
            } else {
                userService.cleanErrorNums(sysUser.getUserName());
                sysUser.setErrorNums(0);
            }
        }
        /**如果想添加某时间段内错误某次后限制
         在第一次密码错误时添加错误时间,再次密码错误时,对比和第一次密码错误的时间
         如在限制时间内 错误次数+1(第一次的错误时间不要覆盖)
         如超过自定义的时间则清除错误时间和错误次数
         */
        if (sysUser.getErrorNums() < UserStatus.WRONG_TIMES) {
            userService.updateErrorNums(sysUser);
            throw new CustomException("还有" + (UserStatus.WRONG_TIMES - sysUser.getErrorNums()) + "次输入机会");
        } else {
            sysUser.setErrorTimes(DateUtils.getTime());
            userService.updateErrorNums(sysUser);
            throw new CustomException("对不起,您的账号:" + sysUser.getUserName() + " 错误次数过多,请" + UserStatus.WRONG_DURATION + "分钟后重试");
        }
    }

增加judgeTime方法。

 private void judgeTime(SysUser sysUser) {
        if (StrUtil.isNotBlank(sysUser.getErrorTimes())) {
            long timeNow = timeToStampSecond(DateUtils.getTime());
            long errorTimes = timeToStampSecond(sysUser.getErrorTimes()) + UserStatus.WRONG_DURATION * 60;
            if (errorTimes - timeNow > 0) {
                String s = formatHMS(errorTimes - timeNow);
                throw new CustomException("对不起,您的账号:" + sysUser.getUserName() + " 错误次数过多,请" + s + "后重试");
            } else {
                //清除次数
                userService.cleanErrorNums(sysUser.getUserName());
            }
        }
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值