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   疯狂的妞妞  阅读(2102)  评论(0编辑  收藏  举报

(评论功能已被禁用)
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
历史上的今天:
2019-01-08 Java反射的一些效率分析
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示