SpringBoot2(十二)当Shiro遇上RedisCache

ShiroCache配置缓存的关键,在于配置SecurityManager,

而SecurityManager的配置,重点只有下面两个,SessionManager和CacheManager ,

其中SessionManager 可以全部默认,无须设计,

需要编码的部分只有 CacheManager ,CacheManager 需要实现CacheManager接口和Cache接口。

securityManager.setSessionManager(SessionManager sessionManager);
securityManager.setCacheManager(CacheManager cacheManager) ;

SecurityManager 与 AuthorizingRealm 相关,Shiro的配置类中找到 AuthorizingRealm ,即可找到 SecurityManager 

  /**
   * 安全管理器
   */
  @Bean
  public SecurityManager securityManager(RedisTemplate<String, Object> redisTemplate) {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setCacheManager(new ShiroRedisCacheManager(redisTemplate));//需要自己实现的部分,本文内容重点
    securityManager.setRealm(new ShiroRealm());//AuthorizingRealm实现,找到你自己Shiro配置的这一行,就知道怎么添加缓存配置
    securityManager.setSessionManager(sessionManager());//代码下面已经给出,全部默认,不是当前讨论的重点
    return securityManager;
  }

  /**
   * session 管理对象
   */
  private DefaultWebSessionManager sessionManager() {
    DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
    sessionManager.setGlobalSessionTimeout(1800000L);
    sessionManager.setSessionDAO(new EnterpriseCacheSessionDAO());
    return sessionManager;
  }

RedisTemplate

Shiro默认缓存是 EhCache,因此代码上会侧重于 JDK 的序列化,因此在使用 Redis 的时候,需要实现一个采用 JDK 序列化的 RedisTemplate。
使用JSON序列化也可以,但是需要额外的设计,这里就不多事了。

 /**
   * RedisTemplate配置--Shiro专属
   */
  @Bean
  public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    RedisSerializer<String> stringSerializer = new StringRedisSerializer();
    JdkSerializationRedisSerializer fastJsonRedisSerializer = new JdkSerializationRedisSerializer();

    redisTemplate.setKeySerializer(stringSerializer);
    redisTemplate.setValueSerializer(fastJsonRedisSerializer);

    redisTemplate.setHashKeySerializer(stringSerializer);
    redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);

    redisTemplate.setConnectionFactory(lettuceConnectionFactory);
    redisTemplate.afterPropertiesSet();
    return redisTemplate;
  }

ShiroRedisCacheManager 

import org.apache.shiro.cache.AbstractCacheManager;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * @author Mr.css
 * @date 2020/1/3
 */
public class ShiroRedisCacheManager extends AbstractCacheManager {

  private RedisTemplate<String,Object> redisTemplate;

  public ShiroRedisCacheManager(RedisTemplate<String,Object> redisTemplate){
    this.redisTemplate = redisTemplate;
  }

  @Override
  protected Cache createCache(String name) throws CacheException {
    return new ShiroRedisCache(redisTemplate,name);
  }
}

ShiroRedisCache 

这样缓存接口已经暴露出来,下面代码仅提供参考,至于如何处理缓存,全看各位的需求了

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;

/**
 * @author Mr.css
 * @date 2020/1/3
 */
public class ShiroRedisCache implements Cache<String, ValidatingSession> {
  private RedisTemplate<String,Object> redisTemplate;
  /**
   * 前缀,用于标识哪些是Shiro的数据,前缀太长,确实会影响查询效率,可以优化
   */
  private String prefix;

  private String getKey(String key){
    return prefix + key;
  }

  ShiroRedisCache(RedisTemplate<String,Object> redisTemplate, String prefix) {
    this.redisTemplate = redisTemplate;
    this.prefix = prefix;
  }

  @Override
  public ValidatingSession get(String key) throws CacheException {
    if (key == null) {
      return null;
    }
    return (ValidatingSession) redisTemplate.opsForValue().get(this.getKey(key));
  }

  @Override
  public ValidatingSession put(String key, ValidatingSession value) throws CacheException {
    if (key == null || value == null) {
      return null;
    }
    redisTemplate.opsForValue().set(this.getKey(key), value);
    return value;
  }

  @Override
  public ValidatingSession remove(String key) throws CacheException {
    if (key == null) {
      return null;
    }
    key = this.getKey(key);
    ValidatingSession value = (ValidatingSession) redisTemplate.opsForValue().get(key);
    redisTemplate.delete(key);
    return value;
  }

  @Override
  public void clear() throws CacheException {
    redisTemplate.delete(this.keys());
  }

  @Override
  public int size() {
    return this.keys().size();
  }

  @Override
  public Set<String> keys() {
    return redisTemplate.keys(prefix + "*");
  }

  @Override
  public Collection<ValidatingSession> values() {
    Set<String> keys = keys();
    List<ValidatingSession> values = new ArrayList<>(keys.size());
    for (String k : keys) {
      values.add((ValidatingSession)redisTemplate.opsForValue().get(k));
    }
    return values;
  }
}

 

posted on 2020-01-08 20:39  疯狂的妞妞  阅读(2071)  评论(0编辑  收藏  举报

导航