在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;
}
}
複製程式碼