分布式Shiro,SpringBoot项目Shiro整合Redis
====================紧张 Begin====================
你的SpringBoot项目已经使用了Shiro,而且可以正常使用。本篇文章的紧张目的是将Shiro生存在服务器内存中的session信息改为使用Redis生存session信息
====================紧张 End====================
正文开始
0、前情概要
由于shiro不支持分布式场景下使用(大概是支持,但没找到),但是现在项目都是分布式的项目,一个服务要摆设多个实例,明显shiro已经无法满足现有的情况。为了使shiro可以在分布式项目中使用,博主查阅了很多资料,此中一个包罗引入shiro-redis依赖来实现(并未实操),但是看这个依赖最新的版本照旧在2020年,果断放弃(应该有很多弊端,我司对弊端的把控极为严格!!!),以是就想着是否可以根据现在把握的技能和网上的实践来手动实现一下shiro整合redis。以下就是博主的实现过程(码多话少,有事滴滴~)
1、引入依赖
- <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配置类
- /**
- * 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;
- }
- }
复制代码- /**
- * RedisCache参数
- */
- @Component
- @Getter
- public class RedisCacheProperties {
- private final Map<String, Duration> cacheDuration = new HashMap<>();
- }
复制代码 3、继承AbstractSessionDAO,创建自界说RedisSessionDao 类
- /**
- * 自定义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
- @Bean
- public SessionManager shiroSessionManager() {
- DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
- //session过期时间
- sessionManager.setGlobalSessionTimeout(expireTime * 1000);
- sessionManager.setSessionDAO(redisSessionDao);
- return sessionManager;
- }
复制代码 问题
往redis中放的数据记得实现 序列化接口,否则会报错!
参考
- 分布式shiro,session共享
- Shiro权限管理框架(二):Shiro结合Redis实现分布式情况下的Session共享
- shiro org.apache.shiro.session.mgt.SimpleSession对象 反序列化失败
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |