在SpringBoot中Shiro緩存使用Redis、Ehcache實現的兩種方式實例
SpringBoot 中配置redis作為session 緩存器。 讓shiro引用
- 本文是建立在你是使用這shiro基礎之上的補充內容
第一種:Redis緩存,將數據存儲到redis 並且開啟session存入redis中。
引入pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
配置redisConfig
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
@Bean
//在這里配置緩存reids配置
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1)); // 設置緩存有效期一小時
System.out.println("《========【開啟redis】 ======== 》 ");
return RedisCacheManager
.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
.cacheDefaults(redisCacheConfiguration).build();
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
配置自定義緩存管理器,引入redis緩存管理器
- 定義自己的CacheManager
/**
* <p> 自定義cacheManage 擴張shiro里面的緩存 使用reids作緩存 </p>
* <description>
* 引入自己定義的CacheManager
* 關於CacheManager的配置文件在spring-redis-cache.xml中
* </description>
*/
@Component
public class ShiroSpringCacheManager implements CacheManager ,Destroyable{
/**
* 將之上的RedisCacheManager的Bean拿出來 注入於此
*/
@Autowired
private org.springframework.cache.CacheManager cacheManager;
public org.springframework.cache.CacheManager getCacheManager() {
return cacheManager;
}
public void setCacheManager(org.springframework.cache.CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public void destroy() throws Exception {
cacheManager = null;
}
@Override
public <K, V> Cache<K, V> getCache(String name) {
if (name == null ){
return null;
}
// 新建一個ShiroSpringCache 將Bean放入並實例化
return new ShiroSpringCache<K,V>(name,getCacheManager());
}
}
- 定義自己實現的Shiro的Cache,實現了Shiro包里的Cache
/**
* <p> 自定義緩存 將數據存入到redis中 </p>
*/
@SuppressWarnings("unchecked")
public class ShiroSpringCache<K,V> implements org.apache.shiro.cache.Cache<K, V>{
private static final Logger log = LoggerFactory.getLogger(ShiroSpringCache.class);
private CacheManager cacheManager;
private Cache cache;
public ShiroSpringCache(String name, CacheManager cacheManager) {
if(name==null || cacheManager==null){
throw new IllegalArgumentException("cacheManager or CacheName cannot be null.");
}
this.cacheManager = cacheManager;
//這里首先是從父類中獲取這個cache,如果沒有會創建一個redisCache,初始化這個redisCache的時候
//會設置它的過期時間如果沒有配置過這個緩存的,那么默認的緩存時間是為0的,如果配置了,就會把配置的時間賦予給這個RedisCache
//如果從緩存的過期時間為0,就表示這個RedisCache不存在了,這個redisCache實現了spring中的cache
this.cache= cacheManager.getCache(name);
}
@Override
public V get(K key) throws CacheException {
log.info("從緩存中獲取key為{}的緩存信息",key);
if(key == null){
return null;
}
ValueWrapper valueWrapper = cache.get(key);
if(valueWrapper==null){
return null;
}
return (V) valueWrapper.get();
}
@Override
public V put(K key, V value) throws CacheException {
log.info("創建新的緩存,信息為:{}={}",key,value);
cache.put(key, value);
return get(key);
}
@Override
public V remove(K key) throws CacheException {
log.info("干掉key為{}的緩存",key);
V v = get(key);
cache.evict(key);//干掉這個名字為key的緩存
return v;
}
@Override
public void clear() throws CacheException {
log.info("清空所有的緩存");
cache.clear();
}
@Override
public int size() {
return cacheManager.getCacheNames().size();
}
/**
* 獲取緩存中所的key值
*/
@Override
public Set<K> keys() {
return (Set<K>) cacheManager.getCacheNames();
}
/**
* 獲取緩存中所有的values值
*/
@Override
public Collection<V> values() {
return (Collection<V>) cache.get(cacheManager.getCacheNames()).get();
}
@Override
public String toString() {
return "ShiroSpringCache [cache=" + cache + "]";
}
}
-
到此為止,使用redis做緩存,和spring的集成就完成了。
-
可以使用以下注解將緩存放入redis
@Cacheable(value = Cache.CONSTANT, key = "'" + CacheKey.DICT_NAME + "'+#name+'_'+#val")
配置spring session管理器
@Bean
@ConditionalOnProperty(prefix = "xpro", name = "spring-session-open", havingValue = "true")
public ServletContainerSessionManager servletContainerSessionManager() {
return new ServletContainerSessionManager();
}
- 新建類 spring session設置session過期時間
/**
* spring session配置
*
* @author xingri
* @date 2017-07-13 21:05
*/
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 900) //session過期時間 如果部署多機環境,需要打開注釋
@ConditionalOnProperty(prefix = "xpro", name = "spring-session-open", havingValue = "true")
public class SpringSessionConfig {
}
第一種:Ehcache做緩存,可以將數據存儲到磁盤中,也可以存到內存中
- 新建ehcache.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" dynamicConfig="false">
<diskStore path="java.io.tmpdir"/>
<!--授權信息緩存-->
<cache name="authorizationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
statistics="true">
</cache>
<!--身份信息緩存-->
<cache name="authenticationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
statistics="true">
</cache>
<!--session緩存-->
<cache name="activeSessionCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
statistics="true">
</cache>
<!-- 緩存半小時 -->
<cache name="halfHour"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="false"
diskPersistent="false" />
<!-- 緩存一小時 -->
<cache name="hour"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="false"
diskPersistent="false" />
<!-- 緩存一天 -->
<cache name="oneDay"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="86400"
timeToLiveSeconds="86400"
overflowToDisk="false"
diskPersistent="false" />
<!--
name:緩存名稱。
maxElementsInMemory:緩存最大個數。
eternal:對象是否永久有效,一但設置了,timeout將不起作用。
timeToIdleSeconds:設置對象在失效前的允許閑置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閑置時間無窮大。
timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。最大時間介於創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。
overflowToDisk:當內存中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁盤中。
diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每個Cache都應該有自己的一個緩沖區。
maxElementsOnDisk:硬盤最大緩存個數。
diskPersistent:是否緩存虛擬機重啟期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。
memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你可以設置為FIFO(先進先出)或是LFU(較少使用)。
clearOnFlush:內存數量最大時是否清除。
-->
<defaultCache name="defaultCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="600"
overflowToDisk="false"
maxElementsOnDisk="100000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
配置自定義緩存管理器,引入ehcache緩存管理器
/**
* ehcache配置
*
*/
@Configuration
@EnableCaching
public class EhCacheConfig {
/**
* EhCache的配置
*/
@Bean
public EhCacheCacheManager cacheManager(CacheManager cacheManager) {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ManagementService.registerMBeans(cacheManager, mBeanServer, true, true, true, true);
return new EhCacheCacheManager(cacheManager);
}
/**
* EhCache的配置
*/
@Bean
public EhCacheManagerFactoryBean ehcache() {
System.out.println("《========【開啟ehcache】 ======== 》 ");
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
return ehCacheManagerFactoryBean;
}
@Bean
public org.apache.shiro.cache.CacheManager getCacheShiroManager(EhCacheManagerFactoryBean ehcache) {
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManager(ehcache.getObject());
return ehCacheManager;
}
}
最后 最重要的是引入shriro 中
/**
* shiro權限管理的配置
*
*/
@Configuration
public class ShiroConfig {
/**
* 安全管理器
*/
@Bean
public DefaultWebSecurityManager securityManager(CookieRememberMeManager rememberMeManager, CacheManager cacheShiroManager, SessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setAuthenticator(modularRealmAuthenticator());
List<Realm> realms=new ArrayList<>();
securityManager.setRealms(realms);
securityManager.setCacheManager(cacheShiroManager);
securityManager.setRememberMeManager(rememberMeManager);
securityManager.setSessionManager(sessionManager);
return securityManager;
}
/**
* spring session管理器(多機環境)
*/
@Bean
public ServletContainerSessionManager servletContainerSessionManager() {
return new ServletContainerSessionManager();
}
/**
* session管理器(單機環境) 使用cookie存儲緩存。。如果多級請注釋
*/
@Bean
public DefaultWebSessionManager defaultWebSessionManager(CacheManager cacheShiroManager, XProProperties xProProperties) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setCacheManager(cacheShiroManager);
sessionManager.setSessionValidationInterval(xProProperties.getSessionValidationInterval() * 1000);
sessionManager.setGlobalSessionTimeout(xProProperties.getSessionInvalidateTime() * 1000);
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
cookie.setName("shiroCookie");
cookie.setHttpOnly(true);
sessionManager.setSessionIdCookie(cookie);
return sessionManager;
}
/**
* 緩存管理器 使用Ehcache實現 如果使用redis則注釋下面內容!!!!
*/
@Bean
public CacheManager getCacheShiroManager(EhCacheManagerFactoryBean ehcache) {
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManager(ehcache.getObject());
return ehCacheManager;
}
/**
* 項目自定義的Realm
*/
@Bean
public ShiroDbRealm shiroDbRealm() {
return new ShiroDbRealm();
}
@Bean
public ShiroTockenRealm shiroTockenRealm( ) {
return new ShiroTockenRealm();
}
@Bean
public ShiroJwtRealm shiroJwtRealm( ) {
return new ShiroJwtRealm();
}
/**
* 系統自帶的Realm管理,主要針對多realm
* */
@Bean
public ModularRealmAuthenticator modularRealmAuthenticator(){
ModularRealmAuthenticator modularRealmAuthenticator=new ModularRealmAuthenticator();
modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
return modularRealmAuthenticator;
}
/**
* rememberMe管理器, cipherKey生成見{@code Base64Test.java}
*/
@Bean
public CookieRememberMeManager rememberMeManager(SimpleCookie rememberMeCookie) {
CookieRememberMeManager manager = new CookieRememberMeManager();
manager.setCipherKey(Base64.decode("Z3VucwAAAAAAAAAAAAAAAA=="));
manager.setCookie(rememberMeCookie);
return manager;
}
/**
* 記住密碼Cookie
*/
@Bean
public SimpleCookie rememberMeCookie() {
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
simpleCookie.setHttpOnly(true);
simpleCookie.setMaxAge(7 * 24 * 60 * 60);//7天
return simpleCookie;
}
/**
* 在方法中 注入 securityManager,進行代理控制
*/
@Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean(DefaultWebSecurityManager securityManager) {
MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean();
bean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
bean.setArguments(new Object[]{securityManager});
return bean;
}
/**
* 保證實現了Shiro內部lifecycle函數的bean執行
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* 啟用shrio授權注解攔截方式,AOP式方法級權限檢查
*/
@Bean
@DependsOn(value = "lifecycleBeanPostProcessor") //依賴其他bean的初始化
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}