在构建基于nbsaas-boot的应用时,Shiro作为一个强大的安全框架,被广泛应用于用户身份认证和权限控制。在实际应用中,为了提高性能并减轻数据库负担,我们通常会使用缓存来存储用户的认证信息和权限信息。本文将介绍如何通过nbsaas-boot适配Shiro Cache,使用Redis和Caffeine作为缓存实现。
Redis缓存实现
首先,我们定义了一个RedisCache类实现Shiro的Cache接口,用于操作Redis缓存。以下是代码实现:
public class RedisCache<K, V> implements Cache<K, V> { private static final String REDIS_SHIRO_CACHE = "nbsaas-cache:"; private String cacheKey; private RedisTemplate<K, V> redisTemplate; private final long globExpire = 30; @SuppressWarnings("rawtypes") public RedisCache(String name, RedisTemplate client) { this.cacheKey = REDIS_SHIRO_CACHE + name + ":"; this.redisTemplate = client; } @Override public V get(K key) throws CacheException { //设置key值过期时间,过期后将删除key值 // redisTemplate.boundValueOps(getCacheKey(key)).expire(globExpire, TimeUnit.MINUTES); //设置key值永不过期 redisTemplate.boundValueOps(getCacheKey(key)); return redisTemplate.boundValueOps(getCacheKey(key)).get(); } @Override public V put(K key, V value) throws CacheException { V old = get(key); redisTemplate.boundValueOps(getCacheKey(key)).set(value); return old; } @Override public V remove(K key) throws CacheException { V old = get(key); redisTemplate.delete(getCacheKey(key)); return old; } @Override public void clear() throws CacheException { redisTemplate.delete(keys()); } @Override public int size() { return keys().size(); } @Override public Set<K> keys() { return redisTemplate.keys(getCacheKey("*")); } @Override public Collection<V> values() { Set<K> set = keys(); List<V> list = new ArrayList<>(); for (K s : set) { list.add(get(s)); } return list; } private K getCacheKey(Object k) { return (K) (this.cacheKey + k); } }
然后,我们创建了一个RedisCacheManager类,实现Shiro的CacheManager接口,用于管理Redis缓存的创建和获取:
public class RedisCacheManager implements CacheManager { @Resource private RedisTemplate<String, Object> redisTemplate; @Override public <K, V> Cache<K, V> getCache(String name) throws CacheException { return new RedisCache<K, V>(name, redisTemplate); } public RedisTemplate<String, Object> getRedisTemplate() { return redisTemplate; } public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) { this.redisTemplate = redisTemplate; } }
Caffeine缓存实现
接下来,我们定义了一个基于Caffeine的ShiroCaffeineCache类实现Shiro的Cache接口,用于操作本地缓存:
public class ShiroCaffeineCache<K, V> implements Cache<K, V> { LoadingCache<K, V> cache; public ShiroCaffeineCache(LoadingCache<K, V> cache) { this.cache = cache; } /** * * @param init 初始容量 * @param max 最大容量 */ public ShiroCaffeineCache(int init,int max) { cache= Caffeine.newBuilder() .initialCapacity(init) .maximumSize(max) .build(key -> null); } /** * * @param init 初始容量 * @param max 最大容量 * @param expireAfterWrite 数据写入以后多久过期时间 * @param expireAfterAccess 数据访问以后多久过期时间 */ public ShiroCaffeineCache(int init,int max,int expireAfterWrite,int expireAfterAccess) { cache= Caffeine.newBuilder() .initialCapacity(init) .maximumSize(max) .expireAfterWrite(expireAfterWrite, TimeUnit.SECONDS) .expireAfterAccess(expireAfterAccess,TimeUnit.SECONDS) .build(key -> null); } @Override public V get(K key) throws CacheException { return cache.getIfPresent(key); } @Override public V put(K key, V value) throws CacheException { cache.put(key, value); return value; } @Override public V remove(K key) throws CacheException { V value = cache.getIfPresent(key); cache.invalidate(key); return value; } @Override public void clear() throws CacheException { cache.invalidateAll(); } @Override public int size() { return (int) cache.estimatedSize(); } @Override public Set<K> keys() { return cache.asMap().keySet(); } @Override public Collection<V> values() { return cache.asMap().values(); } }
最后,我们创建了一个ShiroCaffeineCacheManager类,继承自Shiro的AbstractCacheManager,用于管理Caffeine缓存的创建和获取:
public class ShiroCaffeineCacheManager extends AbstractCacheManager { /** * 初始容量 */ int init; /** * 最大容量 */ int max; /** * 数据写入以后多久过期时间 */ int expireAfterWrite; /** * 数据访问以后多久过期时间 */ int expireAfterAccess; /** * * @param init 初始容量 * @param max 最大容量 * @param expireAfterWrite 数据写入以后多久过期时间 * @param expireAfterAccess 数据访问以后多久过期时间 */ public ShiroCaffeineCacheManager(int init, int max, int expireAfterWrite, int expireAfterAccess) { this.init = init; this.max = max; this.expireAfterWrite = expireAfterWrite; this.expireAfterAccess = expireAfterAccess; } public ShiroCaffeineCacheManager() { this.init = 100; this.max = 5000; this.expireAfterWrite = 60*60; this.expireAfterAccess = 60*30; } @Override protected Cache createCache(String name) throws CacheException { return new ShiroCaffeineCache(init,max,expireAfterWrite,expireAfterAccess); } }
nbsaas-boot适配
为了使上述缓存实现与nbsaas-boot无缝集成,你需要在配置文件中配置相应的Bean。在Spring Boot应用中,可以通过@Configuration注解的类进行配置。
@Bean(name = "securityManager") public DefaultWebSecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(shiroRealm()); securityManager.setSessionManager(sessionManager()); securityManager.setCacheManager(new ShiroCaffeineCacheManager()); return securityManager; } @Bean(name = "shiroFilterFactoryBean") public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); return bean; }
通过上述配置,你就成功地将nbsaas-boot与Shiro缓存进行了集成。在实际应用中,可以根据具体需求进行调整和优化,以满足不同场景的性能和安全需求。希望本文对你在nbsaas-boot项目中使用Shiro缓存提供了一些帮助。