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

运行结果:

猜你喜欢

转载自www.cnblogs.com/Zs-book1/p/11354788.html