zoukankan      html  css  js  c++  java
  • shiro学习笔记:remeberMe,多次登录锁死账号

    关于shiro的rememberme的实现,再之前我们是使用cookie实现的,这里也是一样,原理都是相同的;

    不过因为用到了shiro框架,因此需要再shiro中配置cookie以及缓存等,以及管理器对象:

    <!--安全管理器-->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <!--缓存管理器-->
            <property name="cacheManager" ref="cacheManager"/>
            <!--会话的模式-->
            <property name="sessionMode" value="native"/>
            <!--配置realm-->
            <property name="realms" ref="myRealm"/>
            <property name="rememberMeManager" ref="rememberMeManager"/>
        </bean>
    
        <!--cookie对象-->
        <bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
            <constructor-arg value="rememberMe"/>
            <!--只有http的连接才使用cookie-->
            <property name="httpOnly" value="true"/>
            <!--cookie失效时间-->
            <property name="maxAge" value="#{60*60*24}"/>
        </bean>
        
        <!--记住我管理器对象-->
        <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
            <property name="cookie" ref="simpleCookie"/>
        </bean>

     控制器:

    @Controller
    public class UserController {
    
        private static final transient Logger log = LoggerFactory.getLogger(UserController.class);
        @RequestMapping("/login")
        public String login(User user,String rememberMe) throws Exception  {
    
            Subject currentUser = SecurityUtils.getSubject();
    
            UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
            //记住我
            if (rememberMe != null &&rememberMe.equals("1")) {
                token.setRememberMe(true);
            }
            currentUser.login(token);
            return "redirect:/home";
        }
    }

    前端页面:

    <form action="../login" method="post">
        <input type="text" name="username">
        <input type="password" name="password">
        <input type="checkbox" name="rememberMe" value="1">记住我
        <input type="submit">
    </form>

    配置完成后,再shiro配置文件中对路径进行配置:

    表示emp/下的请求,用户可以访问,然后运行tomcat,输入表单信息,记住我,然后登录,登录成功后,关闭浏览器,关闭浏览器的同时,关闭了session,但是cookie中存有数据,因此可以直接访问/emp/**下的资源,亲测:火狐浏览器如果出不来效果,可能是设置的问题,火狐浏览器,关闭浏览器时自动清空缓存,需要关闭:

    多次登录锁死账号

    多次登录锁死账号:根据这个功能的名称,我们可以构思,我们要将登录信息放在哪儿?如果放在cookie中,每次登录就会刷新登录数据,没有办法记录登录的次数,可以缓存来记录登录次数。具体操作:

    1.配置缓存:

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache name="es">
    
        <diskStore path="java.io.tmpdir"/>
    
        <!--maxEntriesLocalHeap:是用来限制当前缓存在堆内存上所能保存的最大元素数量
        eternal:false 设定缓存的elemen是否永远不过期
        timeToLiveSeconds:对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值为0,表示一直可以访问。(单位:秒)
       timeToIdleSeconds:对象空闲时,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值为0。(单位:秒)
        -->
        <!-- 默认缓存 -->
        <defaultCache
                maxEntriesLocalHeap="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                maxEntriesLocalDisk="10000000"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU"/>
    
        <!-- 登录记录缓存 锁定10分钟 -->
        <cache name="passwordRetryCache"
               maxEntriesLocalHeap="2000"
               eternal="false"
               timeToIdleSeconds="360"
               timeToLiveSeconds="360"
               overflowToDisk="false"
               statistics="true">
        </cache>
    
        <cache name="authorizationCache"
               maxEntriesLocalHeap="2000"
               eternal="false"
               timeToIdleSeconds="3600"
               timeToLiveSeconds="0"
               overflowToDisk="false"
               statistics="true">
        </cache>
    
        <cache name="authenticationCache"
               maxEntriesLocalHeap="2000"
               eternal="false"
               timeToIdleSeconds="3600"
               timeToLiveSeconds="0"
               overflowToDisk="false"
               statistics="true">
        </cache>
    
        <cache name="shiro-activeSessionCache"
               maxEntriesLocalHeap="2000"
               eternal="false"
               timeToIdleSeconds="3600"
               timeToLiveSeconds="0"
               overflowToDisk="false"
               statistics="true">
        </cache>
    
    </ehcache>
    ehcache.xml

    2.在shiro配置文件中,配置缓存的路径:

    3.自定义凭证匹配器,引入缓存

    package com.zs.credentials;
    
    import org.apache.shiro.authc.AuthenticationInfo;
    import org.apache.shiro.authc.AuthenticationToken;
    import org.apache.shiro.authc.ExcessiveAttemptsException;
    import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
    import org.apache.shiro.cache.Cache;
    import org.apache.shiro.cache.CacheManager;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class MyMatcher extends HashedCredentialsMatcher {
    
        //Map:key,value
        //key:存用户名 value:次数
        private Cache<String, AtomicInteger> passwordCache;
    
        public MyMatcher(CacheManager cacheManager) {
            this.passwordCache = cacheManager.getCache("passwordRetryCache");
        }
    
        //密码匹配
        @Override
        public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
            //获取用户名
            String username= (String) token.getPrincipal();
            //先去缓存中查找是否有该信息
            AtomicInteger retryCount= passwordCache.get(username);
            //第一次是null
            if(retryCount==null){
                //初始话:0
                retryCount=new AtomicInteger(0);
                //存入缓存中
                passwordCache.put(username,retryCount);
            }
            //在retryCount上增加1,并获取该值
            if(retryCount.incrementAndGet()>3){
                throw new ExcessiveAttemptsException("该账号已锁定");
            }
            //密码匹配
            boolean matcher=super.doCredentialsMatch(token, info);
            //如果登录成功
            if(matcher){
                //清空缓存数据
                passwordCache.remove(username);
            }
            return matcher;
        }
    }
    自定义的凭证匹配器

    配置该凭证匹配器,并引入缓存:

    然后运行登录测试:输入三次错误密码,在登录,报异常账户锁死:

    异常类:

    package com.zs.controller;
    
    import com.zs.entity.Result;
    import org.apache.shiro.authc.AccountException;
    import org.apache.shiro.authc.ExcessiveAttemptsException;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @ControllerAdvice
    public class ExceptionController {
    
        @ExceptionHandler(Exception.class)
        @ResponseBody
        public Result error(Exception ex, Model model) {
            Result result = new Result();
            if (ex instanceof AccountException) {
                if (ex instanceof ExcessiveAttemptsException) {
                    result.setMessages("账户锁定");
                } else {
                    result.setStats(501);
                    result.setMessages("账号错误");
                }
            } else if (ex instanceof IncorrectCredentialsException) {
                result.setStats(502);
                result.setMessages("密码错误");
            } else {
                result.setStats(503);
                result.setMessages("数据错误");
            }
            return result;
        }
    }
    View Code

    运行结果:

  • 相关阅读:
    Shiro-身份验证
    ORA-12514: TNS: no listener 解决方案
    Oracle创建用户、角色、授权、建表
    ORA-28547:connection to server failed, probable Oracle Net admin error错误,解决方法
    Python学习笔记
    Python学习笔记
    Python学习笔记
    winrm service
    C#动态编译并执行代码
    TypeScript的4种编译方式
  • 原文地址:https://www.cnblogs.com/Zs-book1/p/11354788.html
Copyright © 2011-2022 走看看