> 文档中心 > 后台添加登陆次数限制(Ruoyi若依前后分离版)

后台添加登陆次数限制(Ruoyi若依前后分离版)

上次添加密文传输后 这次添加了登陆次数限制(后台均可使用此方法和思路)

简单来讲就是 同一用户输入密码错误某次以上 限制登陆一段时间

 


实现这个功能分为两点

  1. 记录密码错误次数和错误时间
  2. 密码正确后清除错误次数

数据库添加字段

在记录用户信息的表中添加两个字段

错误次数 error_nums int类型 (设置默认为0)错误时间 error_times varchar类型或datetime类型

添加接口和字段

在你的用户信息(SysUser.java)实体类里添加字段 并生成getset方法

/** * 错误次数 */private int errorNums;/** * 错误时间 */private String errorTimes;

新增两个接口

    /**     * 增加密码错误次数     *     * @param sysUser 用户信息     * @return 结果     */    public int updateErrorNums(SysUser sysUser);    /**     * 清空密码错误次数     *     * @param username 用户名     * @return 结果     */    public int cleanErrorNums(String username);

我的系统使用的myBatis 所以在xml文件要加上字段 和sql

  ... ...   ...         update sys_user set error_nums = if(error_nums is null or LENGTH( trim( error_nums )) = 0, 0, error_nums) + 1, error_times = if(#{errorTimes} is null,now(),#{errorTimes}) where user_name = #{userName}     update sys_user set error_nums = 0 where user_name = #{userName}

查询用户角色的sql也需要加上字段

 if(error_nums is null or LENGTH( trim( error_nums )) = 0, 0, error_nums) + 1

当error_nums为空 或无值时 赋值为0 加1 如有值直接+1

if(#{errorTimes} is null,now(),#{errorTimes})

当参数errorTimes为null 后无值 传当前时间(yyyy-MM-dd HH:mm:ss)格式

注意下系统服务器的时间是否为北京时间 不是 可以用下面设置更改

--mysqlselect NOW();select sysdate();select localtime();show variables like '%time_zone%';set global time_zone = '+8:00';或set global time_zone='Asia/Shanghai'--linux设置时间date -s "20220527 18:30:50"

添加登陆限制接口

/**     * 登陆错误限制     * 更新时sys_user加两字段     * error_nums int类型(默认0!!)     * error_times varchar类型     *     * @param sysUser     */    public void loginError(SysUser sysUser) { //能进来代表用户正常 单纯密码错误 if (sysUser.getErrorNums() > UserStatus.WRONG_TIMES) {     long timeNow = DateUtils.timeToStampSecond(DateUtils.getTime());     long errorTimes = DateUtils.timeToStampSecond(sysUser.getErrorTimes()) + UserStatus.WRONG_DURATION * 60;     if (errorTimes - timeNow > 0) {  String s = DateUtils.formatHMS(errorTimes - timeNow);  throw new CustomException("对不起,您的账号:" + sysUser.getUserName() + " 错误次数过多,请" + s + "后重试");     } } 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 + "分钟后重试"); }    }

timeToStampSecond()是string类型日期转时间戳(秒级)方法

formatHMS() 是long类型时间(秒级)转 天/小时/分钟/秒 大家可以添加下方法

/**     * String类型日期(2021-12-07 10:00:00)转时间戳(秒级)     *     * @param time     * @return     */    public static long timeToStampSecond(String time) { Date d = new Date(); long timeStamp = 0; try {     SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");     d = sf.parse(time);// 日期转换为时间戳 } catch (ParseException e) {     // TODO Auto-generated catch block     e.printStackTrace(); } timeStamp = d.getTime() / 1000; return timeStamp;    }/**     * 秒转天/小时/分钟/秒     *     * @param value     * @return     */    public static String formatHMS(long value) { String str = ""; long i = value / (3600 * 24); if (i > 0) {     str = i + "天"; } value %= 3600 * 24; i = value / 3600; if (i > 0) {     str += i + "时"; } value %= 3600; i = value / 60; if (i > 0) {     str += i + "分"; } value %= 60; str += value + "秒"; return str;    }

WRONG_TIMES和WRONG_DURATION是我添加的枚举类字段 方便之后更改限制次数和时间

    //密码错误次数    public static int WRONG_TIMES = 3;    //密码解锁时长(分钟)    public static int WRONG_DURATION = 5;

现在接口都已写好 就看在哪里使用了

打开SysLoginService.java

     Authentication authentication = null; try {     // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername/decryptByPrivateKey()私钥解密     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());     } }

loginError(userService.selectUserByUserName(username));

要放在catch后 在密码误时引用 如果放在try中 会影响UserDetailsServiceImpl中的账号判断

 最后大家需要跟具自己代码做调整 有什么问题欢迎留言讨论😋