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; } }