在shiro中,登录限制次数

方法如下,

自定义一个匹配器,然后把用户名密码写入ehcache中,然后再读出,判断次数

首先mavne引入jar坐标

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.2.4</version>
</dependency>

第一步,定义匹配器

package cn.taotao.shiro.service;

import java.util.concurrent.atomic.AtomicInteger;

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;

public class MyHashedCredentialsMatcher extends HashedCredentialsMatcher {

    
    private Cache<String, AtomicInteger> passwordRetryCache;
    public MyHashedCredentialsMatcher(CacheManager cacheManager) {
        passwordRetryCache = cacheManager.getCache("passwordRetryCache");
    }

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token,
                                      AuthenticationInfo info) {
        System.out.println("docredentialsmatch......");
        String username = (String) token.getPrincipal();
        // retry count + 1
        AtomicInteger retryCount = passwordRetryCache.get(username);
        if (retryCount == null) {
            retryCount = new AtomicInteger(0);
            passwordRetryCache.put(username, retryCount);
        }
        if (retryCount.incrementAndGet() > 5) {
            // if retry count > 5 throw
            System.out.println("username: " + username + " tried to login more than 5 times in period");
            throw new ExcessiveAttemptsException("username: " + username + " tried to login more than 5 times in period");
        }

        boolean matches = super.doCredentialsMatch(token, info);
        if (matches) {
            // clear retry count
            passwordRetryCache.remove(username);
        }
        return matches;
    }
}

第二步,配置ehache的配置文件,passwordRetryCache为本例修改部分

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <!-- 磁盘保存路径 -->
    <diskStore path="D:44ehcache" />

    <defaultCache maxElementsInMemory="10000"
        maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true"
        timeToIdleSeconds="120" timeToLiveSeconds="120"
        diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU">
    </defaultCache>
     <cache name="passwordRetryCache" eternal="false"  
           maxEntriesLocalHeap="2000"
           timeToIdleSeconds="3600" timeToLiveSeconds="0" overflowToDisk="false"
           statistics="true">
    </cache>
</ehcache>

第三步,配置spring文件,让其加载匹配器,注释掉的部分为之前内容,引用的matcher为新加的内容。在新加入的mathcher中,引用了cachemanager,这个改为自己的ehcache的配置名称。

  <!-- 
        3. 配置 Realm 
        3.1 直接配置实现了 org.apache.shiro.realm.Realm 接口的 bean
    -->     
    <bean id="jdbcRealm" class="cn.taotao.shiro.realms.ShiroRealm">
<!--         <property name="credentialsMatcher"> -->
<!--             <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> -->
<!--                 <property name="hashAlgorithmName" value="MD5"></property> -->
<!--                 <property name="hashIterations" value="1024"></property> -->
<!--             </bean> -->
<!--         </property> -->
         <property name="credentialsMatcher" ref="credentialsMatcher"/>
    </bean>
    
    <bean id="credentialsMatcher" class="cn.taotao.shiro.service.MyHashedCredentialsMatcher">
        <constructor-arg ref="cacheManager"/> 
        <property name="storedCredentialsHexEncoded" value="true"/> 
        <property name="hashAlgorithmName" value="MD5"></property> 
        <property name="hashIterations" value="1024"></property> 
 </bean>

第四步,在前台控制页面加入重新登录次数过多的提示

    @RequestMapping("/login")
    public String login(@RequestParam("username") String username, 
        @RequestParam("password") String password,Map<String ,Object> map) {    
        
        Subject currentUser = SecurityUtils.getSubject();
        
        if (!currentUser.isAuthenticated()) {
            // 把用户名和密码封装为 UsernamePasswordToken 对象
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);

            // rememberme
            token.setRememberMe(true);
            try {
                System.out.println("1. " + token.hashCode());
                // 执行登录. 
                currentUser.login(token);
               
                return "redirect:/index.jsp";
            } 
 
            // 密码重试过多的提示
            catch(ExcessiveAttemptsException ee){
                System.out.println("重试次数过多,请稍后再试");
                map.put("errors","重试次数过多,请稍后再试!");
                return "login";
            }
// 所有认证登录失败的提示
catch (AuthenticationException ae) { //unexpected condition? error? System.out.println("登录失败: " + ae.getMessage()); map.put("errors","Login errors!"); // error.addError(new FieldError("admin", "password", "登录失败")); return "login"; } } return "redirect:/unauthorized.jsp"; }
原文地址:https://www.cnblogs.com/sdgtxuyong/p/12154892.html