Shiro功能應用(八)--Shiro集成RedisTemplate(SDR)

     上一篇文章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緩存。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章