分布式Shiro,SpringBoot项目Shiro整合Redis

分布式Shiro,SpringBoot项目Shiro整合Redis

====================重要 Begin====================

你的SpringBoot项目已经使用了Shiro,并且可以正常使用。本篇文章的主要目的是将Shiro保存在服务器内存中的session信息改为使用Redis保存session信息
====================重要 End====================

正文开始

0、前情概要

由于shiro不支持分布式场景下使用(可能是支持,但没找到),但是现在项目都是分布式的项目,一个服务要部署多个实例,明显shiro已经无法满足现有的情况。为了使shiro可以在分布式项目中使用,博主查阅了很多资料,其中一个包括引入shiro-redis依赖来实现(并未实操),但是看这个依赖最新的版本还是在2020年,果断放弃(应该有很多漏洞,我司对漏洞的把控极为严格!!!),所以就想着是否可以根据目前掌握的技术和网上的实践来手动实现一下shiro整合redis。以下就是博主的实现过程(码多话少,有事滴滴~)

1、引入依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

2、创建Redis配置类

java 复制代码
/**
 * Redis配置类
 */
@EnableCaching
@Configuration
public class RedisConfiguration {

    @Autowired
    RedisCacheProperties redisCacheProperties;

    @Bean()
    public RedisTemplate<String, Object> redisShiroTemplate(@Autowired RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        // shiro序列化存储session存在问题(https://www.cnblogs.com/ReturnOfTheKing/p/18224205)
        /*template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());*/
        return template;
    }

    @Bean(name = {"cacheKeyGenerator"})
    public KeyGenerator cacheKeyGenerator() {
        return (Object o, Method method, Object... objects) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(o.getClass().getName());
            sb.append(method.getName());
            for (Object obj : objects) {
                sb.append(obj.toString());
            }
            return sb.toString();
        };
    }

    @Bean(name = "cacheManager")
    public RedisCacheManager cacheManager(@Autowired RedisConnectionFactory redisConnectionFactory) {

        RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(7))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .disableCachingNullValues();
        RedisCacheManager.RedisCacheManagerBuilder builder =
                RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(redisConnectionFactory);

        Set<String> cacheNames = new HashSet<>();
        ConcurrentHashMap<String, RedisCacheConfiguration> cacheConfig = new ConcurrentHashMap<>();

        for (Map.Entry<String, Duration> entry : redisCacheProperties.getCacheDuration().entrySet()) {
            cacheNames.add(entry.getKey());
            cacheConfig.put(entry.getKey(), defaultConfig.entryTtl(entry.getValue()));
        }

        RedisCacheManager cacheManager = builder
                .transactionAware()
                .cacheDefaults(defaultConfig)
                .initialCacheNames(cacheNames)
                .withInitialCacheConfigurations(cacheConfig)
                .build();

        return cacheManager;
    }
}
java 复制代码
/**
 * RedisCache参数
 */
@Component
@Getter
public class RedisCacheProperties {

    private final Map<String, Duration> cacheDuration = new HashMap<>();
}

3、继承AbstractSessionDAO,创建自定义RedisSessionDao 类

java 复制代码
/**
 * 自定义RedisSessionDAO
 */
@Component
public class RedisSessionDao extends AbstractSessionDAO {

    @Value("${session.redis.expireTime}")
    private long expireTime;

    @Autowired
    private RedisTemplate<String, Object> redisShiroTemplate;

    private String getKey(String originalKey) {
        return "shiro_redis_session_key_:" + originalKey;
    }

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        redisShiroTemplate.opsForValue().set(getKey(session.getId().toString()), session, expireTime, TimeUnit.SECONDS);
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        return sessionId == null ? null : (Session) redisShiroTemplate.opsForValue().get(getKey(sessionId.toString()));
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        if (session != null && session.getId() != null) {
            session.setTimeout(expireTime * 1000);
            redisShiroTemplate.opsForValue().set(getKey(session.getId().toString()), session, expireTime, TimeUnit.SECONDS);
        }
    }

    @Override
    public void delete(Session session) {
        if (session != null && session.getId() != null) {
            redisShiroTemplate.opsForValue().getOperations().delete(getKey(session.getId().toString()));
        }
    }

    @Override
    public Collection<Session> getActiveSessions() {
        return Collections.emptySet();
    }
}

4、在ShiroConfiguration配置类中使用自定义SessionDAO

java 复制代码
@Bean
public SessionManager shiroSessionManager() {
    DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
    //session过期时间
    sessionManager.setGlobalSessionTimeout(expireTime * 1000);
    sessionManager.setSessionDAO(redisSessionDao);
    return sessionManager;
}

问题

往redis中放的数据记得实现 序列化接口,不然会报错!

参考

  1. 分布式shiro,session共享
  2. Shiro权限管理框架(二):Shiro结合Redis实现分布式环境下的Session共享
  3. shiro org.apache.shiro.session.mgt.SimpleSession对象 反序列化失败
相关推荐
JH30734 小时前
SpringBoot 优雅处理金额格式化:拦截器+自定义注解方案
java·spring boot·spring
qq_12498707537 小时前
基于SSM的动物保护系统的设计与实现(源码+论文+部署+安装)
java·数据库·spring boot·毕业设计·ssm·计算机毕业设计
Coder_Boy_7 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端
2301_818732067 小时前
前端调用控制层接口,进不去,报错415,类型不匹配
java·spring boot·spring·tomcat·intellij-idea
此生只爱蛋8 小时前
【Redis】主从复制
数据库·redis
汤姆yu11 小时前
基于springboot的尿毒症健康管理系统
java·spring boot·后端
暮色妖娆丶11 小时前
Spring 源码分析 单例 Bean 的创建过程
spring boot·后端·spring
biyezuopinvip12 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
惊讶的猫12 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
JavaGuide12 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot