在构建基于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缓存提供了一些帮助。