方法如下,
自定义一个匹配器,然后把用户名密码写入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"; }