天天看点

Spring Boot系列(十五) 安全框架Apache Shiro(二)缓存-EhCache

本例在上一节Shiro基本功能基础上增加缓存功能,主要缓存Session、身份、权限等,对于实际应用会减少查询数据库次数,提升效率。Shiro为我们提供了CacheManager接口,在1.2.x版本中,提供了EhCache缓存的实现EhCacheManager和默认的MemoryConstrainedCacheManager的实现,到1.3.x版本时,增加了基于Hazelcast的分布式缓存实现HazelcastCacheManager。

通常在单应用中使用EhCache的缓存实现。在上一实例基础上添加EhCache缓存,具体步骤如下:

步骤1:在classpath下添加ehcache.xml配置文件:/META-INF/ehcache/ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="es">
    <diskStore path="java.io.tmpdir"/>
    <!--
       name:缓存名称。
       maxElementsInMemory:缓存最大数目
       maxElementsOnDisk:硬盘最大缓存个数。 
       eternal:对象是否永久有效,一但设置了,timeout将不起作用。 
       overflowToDisk:是否保存到磁盘,当系统当机时
       timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
       timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
       diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false. 
       diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。 
       diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
       memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。 
       clearOnFlush:内存数量最大时是否清除。
       memoryStoreEvictionPolicy:
       Ehcache的三种清空策略;
          FIFO,first in first out,这个是大家最熟的,先进先出。
          LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
          LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
    -->
    <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>
           

步骤2:在ShiroConfiguration配置类中,创建缓存管理器@Bean

/**
* Shiro CacheManager 定义 Shiro 缓存管理器
* 
* 需要加入到安全管理器:securityManager
* @return
*/
@Bean
public EhCacheManager ehCacheManager() {
    logger.info("注入Shiro的缓存管理器-->ehCacheManager", EhCacheManager.class);
    EhCacheManager cacheManager = new EhCacheManager();
    cacheManager.setCacheManagerConfigFile("classpath:META-INF/ehcache/ehcache.xml");
    return cacheManager;
}
           

步骤3:将缓存管理器注入到SecurityManager中

@Bean
public SecurityManager securityManager() {
    logger.info("注入Shiro的Web过滤器-->securityManager", ShiroFilterFactoryBean.class);
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    //设置Realm,用于获取认证凭证
    securityManager.setRealm(userRealm());
    //注入EhCacheManager缓存管理器
    securityManager.setCacheManager(ehCacheManager());
    return securityManager;
}
           

步骤4:在realm中开启缓存(默认是false)

@Bean
public UserRealm userRealm() {
    UserRealm userRealm = new UserRealm();
    //告诉realm,使用credentialsMatcher加密算法类来验证密文
    userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
    //启用缓存,默认false
    userRealm.setCachingEnabled(true);
    //  启用身份验证缓存,即缓存AuthenticationInfo信息,默认false;
    userRealm.setAuthenticationCachingEnabled(true);
    //  缓存AuthenticationInfo信息的缓存名称,即配置在ehcache.xml中的cache name
    userRealm.setAuthenticationCacheName("authenticationCache");
    //  启用授权缓存,即缓存AuthorizationInfo信息,默认false;
    userRealm.setAuthorizationCachingEnabled(true);
    //  缓存AuthorizationInfo信息的缓存名称;
    userRealm.setAuthorizationCacheName("authorizationCache");

    return userRealm;
}
           

测试:

  1. 比如登陆后,1小时不刷新页面,session会自动失效(timeToIdleSeconds=”3600”)
  2. 前段获取角色、权限等信息,第一次获取时,回去数据库查询(发出sql语句),在有效时间内,再次获取时,直接从缓存中获取。

继续阅读