ShiroCache重點在於配置SecurityManager,關鍵配置只有下面兩個,SessionManager和CacheManager ,其中SessionManager 可以全部默認,無須設計,
重點在 CacheManager 上,CacheManager 需要實現CacheManager接口和Cache接口。
securityManager.setSessionManager(SessionManager sessionManager);
securityManager.setCacheManager(CacheManager cacheManager) ;
SecurityManager 與 AuthorizingRealm 相關,配置中找到 AuthorizingRealm 實現類,即可找到 SecurityManager
/** * 安全管理器 */ @Bean public SecurityManager securityManager(RedisTemplate<String, Object> redisTemplate) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setCacheManager(new ShiroRedisCacheManager(redisTemplate));//需要自己實現的部分,本文內容重點 securityManager.setRealm(new ShiroRealm());//AuthorizingRealm實現,找到你自己Shiro配置的這一行,就知道怎么添加緩存配置 securityManager.setSessionManager(sessionManager());//代碼下面已經給出,全部默認,不是當前討論的重點 return securityManager; } /** * session 管理對象 */ private DefaultWebSessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setGlobalSessionTimeout(1800000L); sessionManager.setSessionDAO(new EnterpriseCacheSessionDAO()); return sessionManager; }
RedisTemplate
Shiro默認緩存是 EhCache,因此代碼上會側重於 JDK 的序列化,因此在使用 Redis 的時候,需要實現一個采用 JDK 序列化的 RedisTemplate。
使用JSON序列化也可以,但是需要額外的設計,這里就不多事了。
/** * RedisTemplate配置--Shiro專屬 */ @Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); RedisSerializer<String> stringSerializer = new StringRedisSerializer(); JdkSerializationRedisSerializer fastJsonRedisSerializer = new JdkSerializationRedisSerializer(); redisTemplate.setKeySerializer(stringSerializer); redisTemplate.setValueSerializer(fastJsonRedisSerializer); redisTemplate.setHashKeySerializer(stringSerializer); redisTemplate.setHashValueSerializer(fastJsonRedisSerializer); redisTemplate.setConnectionFactory(lettuceConnectionFactory); redisTemplate.afterPropertiesSet(); return redisTemplate; }
ShiroRedisCacheManager
import org.apache.shiro.cache.AbstractCacheManager; import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheException; import org.springframework.data.redis.core.RedisTemplate; /** * @author Mr.css * @date 2020/1/3 */ public class ShiroRedisCacheManager extends AbstractCacheManager { private RedisTemplate<String,Object> redisTemplate; public ShiroRedisCacheManager(RedisTemplate<String,Object> redisTemplate){ this.redisTemplate = redisTemplate; } @Override protected Cache createCache(String name) throws CacheException { return new ShiroRedisCache(redisTemplate,name); } }
ShiroRedisCache
這樣緩存接口已經暴露出來,至於如何處理緩存,全看個人喜好
import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheException; import org.apache.shiro.session.mgt.ValidatingSession; import org.springframework.data.redis.core.RedisTemplate; import java.util.*; /** * @author Mr.css * @date 2020/1/3 */ public class ShiroRedisCache implements Cache<String, ValidatingSession> { private RedisTemplate<String,Object> redisTemplate; /** * 前綴,用於標識哪些是Shiro的數據,前綴太長,確實會影響查詢效率,可以優化 */ private String prefix; private String getKey(String key){ return prefix + key; } ShiroRedisCache(RedisTemplate<String,Object> redisTemplate, String prefix) { this.redisTemplate = redisTemplate; this.prefix = prefix; } @Override public ValidatingSession get(String key) throws CacheException { if (key == null) { return null; } return (ValidatingSession) redisTemplate.opsForValue().get(this.getKey(key)); } @Override public ValidatingSession put(String key, ValidatingSession value) throws CacheException { if (key == null || value == null) { return null; } redisTemplate.opsForValue().set(this.getKey(key), value); return value; } @Override public ValidatingSession remove(String key) throws CacheException { if (key == null) { return null; } key = this.getKey(key); ValidatingSession value = (ValidatingSession) redisTemplate.opsForValue().get(key); redisTemplate.delete(key); return value; } @Override public void clear() throws CacheException { redisTemplate.delete(this.keys()); } @Override public int size() { return this.keys().size(); } @Override public Set<String> keys() { return redisTemplate.keys(prefix + "*"); } @Override public Collection<ValidatingSession> values() { Set<String> keys = keys(); List<ValidatingSession> values = new ArrayList<>(keys.size()); for (String k : keys) { values.add((ValidatingSession)redisTemplate.opsForValue().get(k)); } return values; } }