1.先上shiro.xml中的配置 将缓存管理器配置进去
<!-- 缓存管理器 使用Ehcache实现 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
</bean>
<!-- 自定义凭证匹配器-->
<bean id="credentialsMatcher" class="cn.cjq.util.shiro.RetryLimitHashedCredentialsMatcher">
<constructor-arg ref="cacheManager"/>
<property name="hashAlgorithmName" value="md5"/>
<property name="hashIterations" value="1"/>
<property name="storedCredentialsHexEncoded" value="true"/>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
<property name="realm" ref="myShiroRealm"/>
<property name="sessionManager" ref="sessionManager"/>
<property name="cacheManager" ref="cacheManager"/>
<!-- 记住我 -->
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>
--------------------------------------------------------------------------------------------------------
2.上ehcache.xml配置文件 记录缓存参数
<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="shirocache">
<diskStore path="java.io.tmpdir"/>
<defaultCache
name="defaut"
maxElementsInMemory="5"
eternal="false"
timeToIdleSeconds="20"
timeToLiveSeconds="20"
overflowToDisk="false"
diskPersistent="false"
memoryStoreEvictionPolicy="LRU"
/>
<!-- 登录记录缓存 锁定10分钟 -->
<cache name="passwordRetryCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
>
</cache>
<!-- 授权缓存 -->
<cache name="authorizationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
>
</cache>
<!-- 认证缓存 -->
<cache name="authenticationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
>
</cache>
<cache name="shiro-activeSessionCache"
maxEntriesLocalHeap="10000"
eternal="false"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
>
</cache>
</ehcache>
-----------------------------------------------------------------------------------------------------------------------
3.自定义凭证匹配器 缓存使用实例 密码错误大于五次抛ExcessiveAttemptsException异常
package cn.cjq.util.shiro;
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 RetryLimitHashedCredentialsMatcher extends
HashedCredentialsMatcher {
private Cache<String, AtomicInteger> passwordRetryCache;
public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
passwordRetryCache = cacheManager.getCache("passwordRetryCache");
}
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
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
throw new ExcessiveAttemptsException();
}
boolean matches = super.doCredentialsMatch(token, info);
if(matches) {
//clear retry count
passwordRetryCache.remove(username);
}
return matches;
}
}
----------------------------------------------------------------------------------------------------------------------------
4.缓存实例 注入cacheManager
@Resource
private CacheManager cacheManager;
//获取
Cache<String, AtomicInteger> passwordRetryCache=cacheManager.getCache("passwordRetryCache");
//捕捉认证异常
catch (AuthenticationException e) {
//参数认证异常
return new Response("999999","输入参数有误,您还有" +(6-passwordRetryCache.get(userName).get())+"次机会重新输入!");
}
------------------------------------------------------------------------------------------------------
附录:AtomicInteger类 AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。十分适合高并发情况下的使用
在使用Integer的时候,必须加上synchronized保证不会出现并发线程同时访问的情况,而在AtomicInteger中却不用加上synchronized,在这里AtomicInteger是提供原子操作的。
AtomicInteger运算
- public class Test {
- public static void main(String[] args) {
- AtomicInteger integer = new AtomicInteger();
- integer.set(1);
- int i = integer.get(); //获得值
- System.out.println(i);
- i = integer.incrementAndGet(); //先+1,然后在返回值,相当于++i
- System.out.println(i);
- i = integer.getAndIncrement();//先返回值,然后在+1,相当于i++
- System.out.println(i);
- i = integer.get();
- System.out.println(i);
- i = integer.decrementAndGet();//先-1,然后在返回值,相当于--i
- System.out.println(i);
- i = integer.getAndDecrement();//先返回值,然后在-1,相当于i--
- System.out.println(i);
- i = integer.get();
- System.out.println(i);//1
- i = integer.addAndGet(1);//先+n,然后在返回值,
- System.out.println(i);
- i = integer.getAndAdd(1);//先返回,然后+n
- System.out.println(i);
- i = integer.get();
- System.out.println(i);
- }
- }
----------------------------------------------------------------------------------------------------------------------------------------------
附录2
主要的特性有:
1. 快速
2. 简单
3. 多种缓存策略
4. 缓存数据有两级:内存和磁盘,因此无需担心容量问题
5. 缓存数据会在虚拟机重启的过程中写入磁盘
6. 可以通过RMI、可插入API等方式进行分布式缓存
7. 具有缓存和缓存管理器的侦听接口
8. 支持多缓存管理器实例,以及一个实例的多个缓存区域
9. 提供Hibernate的缓存实现
ehcache.xml:里面的注释写的很清楚了。
<diskStore> : 当内存缓存中对象数量超过maxElementsInMemory时,将缓存对象写到磁盘缓存中(需对象实现序列化接口)
<diskStore path=""> : 用来配置磁盘缓存使用的物理路径,Ehcache磁盘缓存使用的文件后缀名是*.data和*.index
name : "缓存名称,cache的唯一标识(ehcache会把这个cache放到HashMap里)
maxElementsInMemory : 缓存最大个数。
eternal="false" : 对象是否永久有效,一但设置了,timeout将不起作用。 (必须设置)
maxEntriesLocalHeap="1000" : 堆内存中最大缓存对象数,0没有限制(必须设置)
maxEntriesLocalDisk= "1000" : 硬盘最大缓存个数。
overflowToDisk="false" : 当缓存达到maxElementsInMemory值是,是否允许溢出到磁盘(必须设置)(内存不足时,是否启用磁盘缓存。)
diskSpoolBufferSizeMB : 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskPersistent="false" : 磁盘缓存在JVM重新启动时是否保持(默认为false)
timeToIdleSeconds="0" : 导致元素过期的访问间隔(秒为单位),即当缓存闲置n秒后销毁。 当eternal为false时,这个属性才有效,0表示可以永远空闲,默认为0
timeToLiveSeconds="600" : 元素在缓存里存在的时间(秒为单位),即当缓存存活n秒后销毁. 0 表示永远存在不过期
memoryStoreEvictionPolicy="LFU" : 当达到maxElementsInMemory时,如何强制进行驱逐默认使用"最近使用(LRU)"策略,其它还有先入先出FIFO,最少使用LFU,较少使用LRU
diskExpiryThreadIntervalSeconds :磁盘失效线程运行时间间隔,默认是120秒。
clearOnFlush : 内存数量最大时是否清除。