上一篇文章Shiro功能應用(七)–Shiro集成Redis緩存(shiro-redis3.1.0)中提到,繼承shiro-redis,授權的User實體類要有AuthCacheKey或者Id屬性,這有一定侷限性,本文在上一篇文章代碼基礎上,修改成集成SDR(spring-boot-starter-data-redis依賴)
代碼實現:
代碼地址:
https://github.com/OooooOz/SpringBoot-Shiro
自定義緩存處理器
繼承CacheManager,重寫getCache方法,方法返回自定義緩存類(實現cache接口,重寫get、remove等方法)。
hashKey()方法對獲取緩存做兼容,shiro緩存中獲取認證if的key是username,而緩存獲取權限info的key是user對象,所以做個區分。
//redis緩存實現類
package com.demo.config;
import java.util.Collection;
import java.util.Set;
import javax.annotation.Resource;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import com.demo.entity.User;
@Component
public class RedisCacheManager implements CacheManager {
private String cacheKeyPrefix = "shiro:";
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
return new ShiroRedisCache<K,V>(cacheKeyPrefix+name);
}
/**
* 爲shiro量身定做的一個redis cache,爲Authorization cache做了特別優化
*/
public class ShiroRedisCache<K, V> implements Cache<K, V> {
private String cacheKey;
public ShiroRedisCache(String cacheKey) {
this.cacheKey=cacheKey;
}
@Override
public V get(K key) throws CacheException {
BoundHashOperations<String,K,V> hash = redisTemplate.boundHashOps(cacheKey);
Object k=hashKey(key);
V v = hash.get(k);
return v;
}
@Override
public V put(K key, V value) throws CacheException {
BoundHashOperations<String,K,V> hash = redisTemplate.boundHashOps(cacheKey);
Object k=hashKey(key);
hash.put((K)k, value);
return value;
}
@Override
public V remove(K key) throws CacheException {
BoundHashOperations<String,K,V> hash = redisTemplate.boundHashOps(cacheKey);
Object k=hashKey(key);
V value=hash.get(k);
hash.delete(k);
return value;
}
@Override
public void clear() throws CacheException {
redisTemplate.delete(cacheKey);
}
@Override
public int size() {
BoundHashOperations<String,K,V> hash = redisTemplate.boundHashOps(cacheKey);
return hash.size().intValue();
}
@Override
public Set<K> keys() {
BoundHashOperations<String,K,V> hash = redisTemplate.boundHashOps(cacheKey);
return hash.keys();
}
@Override
public Collection<V> values() {
BoundHashOperations<String,K,V> hash = redisTemplate.boundHashOps(cacheKey);
return hash.values();
}
protected Object hashKey(K key) {
//此處很重要,如果key是登錄憑證,那麼這是訪問用戶的授權緩存;將登錄憑證轉爲user對象,
//返回user的name屬性做爲hash key,否則會以user對象做爲hash key,這樣就不好清除指定用戶的緩存了
if(key instanceof PrincipalCollection) {
PrincipalCollection pc=(PrincipalCollection) key;
User user =(User)pc.getPrimaryPrincipal();
return user.getUserName();
}else if (key instanceof User) {
User user =(User) key;
return user.getUserName();
}
return key;
}
}
}
ShiroConfig的注入自定義緩存管理器*以及redisTemplate
/**
* 注入redisTemplate工具
* */
@Bean
public StringRedisTemplate redisTemplate(JedisConnectionFactory jedisConnectionFactory){
StringRedisTemplate redisTemplate = new StringRedisTemplate(jedisConnectionFactory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer); //鍵值序列化方式
redisTemplate.setValueSerializer(jdkSerializationRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer); //綁定hash的序列化方式
redisTemplate.setHashValueSerializer(jdkSerializationRedisSerializer);
// redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
/**
* Jedis連接工廠,Springboot2.0以上採用redisStandaloneConfiguration
* */
@Bean
public JedisConnectionFactory jedisConnectionFactory(RedisStandaloneConfiguration redisStandaloneConfiguration){
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
return jedisConnectionFactory;
}
//JedisConnectionFactory注入的redis配置
@Bean
public RedisStandaloneConfiguration redisStandaloneConfiguration(){
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName("192.168.2.104");
redisStandaloneConfiguration.setPort(6379);
//redisStandaloneConfiguration.setPassword(RedisPassword);
return redisStandaloneConfiguration;
}
/**
* 自定義封裝的redis緩存操作類
* */
@Bean("redisCacheManager")
public RedisCacheManager redisCacheManager(){
RedisCacheManager redisCacheManager = new RedisCacheManager();
return redisCacheManager;
}
KickOut過濾器修改:
之前EHCache緩存時,隊列可以先放緩存,再往緩存的隊列push值。險種Redis做緩存,需要先將sessionId值放入隊列,隊列再放入緩存:
功能測試:
打開兩個瀏覽器登錄,會有一個被踢出來,集成完畢。從RDM裏可以看到redis緩存。