springboot项目应用ehcahe-shiro限制短信登录失败次数

需求背景

用户使用手机号和短信验证码登录,项目要求限制用户登录失败的次数,即失败超过6次,就锁定用户账号。

实现思路

以登陆者手机号码 + “errorTimes” 为 key 值进行记录。验证码输入错误后记录次数,验证码输入错误次数达到 6 次以后,将该用户状态设置为锁定。

技术选择

1、MySql 新增缓存表进行记录;
2、使用 ehcache 进行缓存;
3、使用 redis 进行缓存;
进过比较,ehcache 比较契合我们项目的现状,故此选择。
(在网上找到了相关限制登录次数的方法,单都是账号密码登录。取得是数据库中密码而非短信验证码,所以只能自己写了)

实现代码

1、在 main/resources 下新建 config 文件夹,在 config 中新建 ehcache-shiro.xml 文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="es">

    <diskStore path="java.io.tmpdir"/>

    <!--
       name:缓存名称。
       maxElementsInMemory:缓存最大数目
       maxElementsOnDisk:硬盘最大缓存个数。
       eternal:对象是否永久有效,一但设置了,timeout将不起作用。
       overflowToDisk:是否保存到磁盘,当系统当机时
       timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
                TTI用于设置对象在cache中的最大闲置时间,就是 在一直不访问这个对象的前提下,这个对象可以在cache中的存活时间。
       timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
             TTL用于设置对象在cache中的最大存活时间,就是 无论对象访问或是不访问(闲置),这个对象在cache中的存活时间。
       diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
       diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
       diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
       memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
        clearOnFlush:内存数量最大时是否清除。
         memoryStoreEvictionPolicy:
            Ehcache的三种清空策略;
            FIFO,first in first out,这个是大家最熟的,先进先出。
            LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
            LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
    -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
    />


    <!-- 登录错误记录缓存锁定24小时 -->
    <cache name="errorLoginCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="0"
           timeToLiveSeconds="86400"
           overflowToDisk="false"
           statistics="true">
    </cache>

</ehcache>

。java

2、在校验验证码的方法 smsServiceImpl.java 中,写入内容如下:

(验证码对比方法:前端传过来的验证码和发送短信后存储在 session 中的验证码对比)

	@Override
    public boolean verifySms(String mobile, String code, HttpSession httpSession) {
        // 获取 session 验证码
        String sessionString = (String) httpSession.getAttribute("sms_login_" + mobile);
        //1,创建缓存管理器
        CacheManager cm = CacheManager.create(this.getClass().getResourceAsStream("/config/ehcache-shiro.xml"));
        //2,获取指定的缓存
        Cache cache = cm.getCache("errorLoginCache");
        Element element  = cache.get(mobile+"errorTimes");
        if (sessionString != null) {
            // 字符串前四位是验证码,后面是创建时间
            String sessionCode = sessionString.substring(0, 4);
            // 比较验证码是否一致  return sessionCode.equals(code);
            Integer count = 0;
            if (!sessionCode.equals(code)){
                //4,判断数据
                if (element == null) {
                    //如果用户没有登陆过,登陆次数加1 并放入缓存
                    cache.put(new Element(mobile+"errorTimes", 1));
                } else {
                    count = (Integer) element.getObjectValue();
                    if (count > 4){ // 从0到4, 点击6次锁定,所以需要大于4
                        SysEmployee sysEmployee = sysEmployeeService.findByMobile(mobile);
                        if (sysEmployee != null && sysEmployee.getStatus() != -1 ){
                            //修改数据库的状态字段为锁定
                            sysEmployee.setStatus(-1);
                            sysEmployeeService.update(sysEmployee);
                        }
                    }else{
                        cache.put(new Element(mobile+"errorTimes", count+1));
                    }

                }
            }else{
                // 登录成功,删除缓存中的登录错误次数
                cache.remove(mobile+"errorTimes");
                return true;
            }
        }
        return false;
    }
3、在登录方法中,调用上述校验结果判断即可:
 if (smsService.verifySms(mobile, code, httpSession)){
        try {
            Subject subject = getSubject();
            if (subject != null)
                subject.logout();
            subject.login(token);
            // 更新登陆记录
            sysEmployeeService.saveLoginInfo(getCurrentUser());
            return "redirect:/";
        } catch (UnknownAccountException | IncorrectCredentialsException | LockedAccountException e) {
            attributes.addFlashAttribute("type", "error");
            attributes.addFlashAttribute("msg", e.getMessage());
            attributes.addFlashAttribute("mobile", mobile);
            return "redirect:/login";
        } catch (AuthenticationException e) {
            attributes.addFlashAttribute("type", "error");
            attributes.addFlashAttribute("msg", "认证失败");
            attributes.addFlashAttribute("mobile", mobile);
            return "redirect:/login";
        }
    }else{
        if (sysEmployee.getStatus() != -1){
            attributes.addFlashAttribute("type", "error");
            attributes.addFlashAttribute("msg", "验证码错误");
            attributes.addFlashAttribute("mobile", mobile);
        }else{
            attributes.addFlashAttribute("type", "error");
            attributes.addFlashAttribute("msg", "账号已被锁定,请联系管理员");
            attributes.addFlashAttribute("mobile", mobile);
        }
        return "redirect:/login";
    }

第一下次使用 ehcache,难免有错误疏漏 ,如有不足还请指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值