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缓存。
在这里插入图片描述

发布了17 篇原创文章 · 获赞 18 · 访问量 4548

猜你喜欢

转载自blog.csdn.net/weixin_43901882/article/details/105791360