Spring Boot + Redis 实现Shiro集群
为实现Web应用的分布式集群部署,要解决登录session的统一。本文利用shiro做权限控制,redis做session存储,结合spring boot快速配置实现session共享。
1、引入相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
2、Redis相关
2.1.redis配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
2.2.redis缓存的对象必须序列化,通用序列化
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException; /**
* redis序列化对象
*/
public class RedisObjectSerializer implements RedisSerializer<Object> {
private Converter<Object, byte[]> serializer = new SerializingConverter();
private Converter<byte[], Object> deserializer = new DeserializingConverter();
static final byte[] EMPTY_ARRAY = new byte[0]; public Object deserialize(byte[] bytes) {
if (isEmpty(bytes)) {
return null;
}
try {
return deserializer.convert(bytes);
} catch (Exception ex) {
throw new SerializationException("Cannot deserialize", ex);
}
} public byte[] serialize(Object object) {
if (object == null) {
return EMPTY_ARRAY;
}
try {
return serializer.convert(object);
} catch (Exception ex) {
return EMPTY_ARRAY;
}
} private boolean isEmpty(byte[] data) {
return (data == null || data.length == 0);
}
}
2.3 RedisTemplate 配置
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer; /**
* redis 配置
*/
@Configuration
public class RedisConfig { @Bean
public CacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
cacheManager.setDefaultExpiration(1800);
return cacheManager;
} @Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new RedisObjectSerializer());
return template;
}
}
3.Redis实现shiro的SessionDao存取session
import java.io.Serializable;
import java.util.concurrent.TimeUnit; import javax.annotation.Resource; import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component; /**
* redis实现共享session
*/
@Component
public class RedisSessionDAO extends EnterpriseCacheSessionDAO { private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class); // session 在redis过期时间是30分钟30*60
private static int expireTime = 1800; private static String prefix = "weiyou-shiro-session:"; @Resource
private RedisTemplate<String, Object> redisTemplate; // 创建session,保存到数据库
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = super.doCreate(session);
logger.debug("创建session:{}", session.getId());
redisTemplate.opsForValue().set(prefix + sessionId.toString(), session);
return sessionId;
} // 获取session
@Override
protected Session doReadSession(Serializable sessionId) {
logger.debug("获取session:{}", sessionId);
// 先从缓存中获取session,如果没有再去数据库中获取
Session session = super.doReadSession(sessionId);
if (session == null) {
session = (Session) redisTemplate.opsForValue().get(prefix + sessionId.toString());
}
return session;
} // 更新session的最后一次访问时间
@Override
protected void doUpdate(Session session) {
super.doUpdate(session);
logger.debug("获取session:{}", session.getId());
String key = prefix + session.getId().toString();
if (!redisTemplate.hasKey(key)) {
redisTemplate.opsForValue().set(key, session);
}
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
} // 删除session
@Override
protected void doDelete(Session session) {
logger.debug("删除session:{}", session.getId());
super.doDelete(session);
redisTemplate.delete(prefix + session.getId().toString());
}
}
4.实现cache共享
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit; import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate; @SuppressWarnings("unchecked")
public class ShiroCache<K, V> implements Cache<K, V> { private static final String REDIS_SHIRO_CACHE = "weiyou-shiro-cache:";
private String cacheKey;
private RedisTemplate<K, V> redisTemplate;
private long globExpire = 30; @SuppressWarnings("rawtypes")
public ShiroCache(String name, RedisTemplate client) {
this.cacheKey = REDIS_SHIRO_CACHE + name + ":";
this.redisTemplate = client;
} @Override
public V get(K key) throws CacheException {
redisTemplate.boundValueOps(getCacheKey(key)).expire(globExpire, TimeUnit.MINUTES);
return redisTemplate.boundValueOps(getCacheKey(key)).get();
} @Override
public V put(K key, V value) throws CacheException {
V old = get(key);
redisTemplate.boundValueOps(getCacheKey(key)).set(value);
return old;
} @Override
public V remove(K key) throws CacheException {
V old = get(key);
redisTemplate.delete(getCacheKey(key));
return old;
} @Override
public void clear() throws CacheException {
redisTemplate.delete(keys());
} @Override
public int size() {
return keys().size();
} @Override
public Set<K> keys() {
return redisTemplate.keys(getCacheKey("*"));
} @Override
public Collection<V> values() {
Set<K> set = keys();
List<V> list = new ArrayList<>();
for (K s : set) {
list.add(get(s));
}
return list;
} private K getCacheKey(Object k) {
return (K) (this.cacheKey + k);
}
}
实现shiro 的CacheManager
import javax.annotation.Resource; import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate; public class RedisCacheManager implements CacheManager { @Resource
private RedisTemplate<String, Object> redisTemplate; @Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
return new ShiroCache<K, V>(name, redisTemplate);
} public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
} public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
} }
5.配置
import java.util.HashMap;
import java.util.Map; import javax.annotation.Resource; import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
*
* @author April.Chen
*/
//@Configuration
public class ShiroConfig { @Resource
private RedisSessionDAO sessionDAO; @Bean
public UserRealm getUserRealm() {
return new UserRealm();
} @Bean
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
} @Bean
public RedisCacheManager redisCacheManager() {
return new RedisCacheManager();
} @Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(sessionDAO);
sessionManager.setGlobalSessionTimeout(1800);
sessionManager.setCacheManager(redisCacheManager());
return sessionManager;
} @Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setSessionManager(sessionManager());
securityManager.setCacheManager(redisCacheManager());
return securityManager;
} @Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
aasa.setSecurityManager(securityManager());
return new AuthorizationAttributeSourceAdvisor();
} @Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
daap.setProxyTargetClass(true);
return daap;
} @Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
Map<String, String> filterChainDefinitionMap = new HashMap<>();
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager());
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
filterChainDefinitionMap.put("/sa/**", "authc");
filterChainDefinitionMap.put("/**", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
}
Spring Boot + Redis 实现Shiro集群的更多相关文章
- Spring Boot集成Hazelcast实现集群与分布式内存缓存
Hazelcast是Hazelcast公司开源的一款分布式内存数据库产品,提供弹性可扩展.高性能的分布式内存计算.并通过提供诸如Map,Queue,ExecutorService,Lock和JCach ...
- Spring Boot项目配置RabbitMQ集群
//具体参看了配置的源码 org.springframework.boot.autoconfigure.amqp.RabbitProperties //RabbitMQ单机 spring: rab ...
- spring + spring-data-redist + Redis 单机、集群(cluster模式,哨兵模式)
一.单机redis配置 1. 配置redis连接池 <bean id="jedisPoolConfig" class="redis.clients.jedis.Je ...
- Apache shiro集群实现 (七)分布式集群系统下---cache共享
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Redis 高可用集群
Redis 高可用集群 Redis 的集群主从模型是一种高可用的集群架构.本章主要内容有:高可用集群的搭建,Jedis连接集群,新增集群节点,删除集群节点,其他配置补充说明. 高可用集群搭建 集群(c ...
- Apache shiro集群实现 (八) web集群时session同步的3种方法
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (五)分布式集群系统下的高可用session解决方案
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (四)shiro授权(Authentication)--访问控制
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
随机推荐
- 图像特征提取之Haar特征
1.Haar-like特征 Haar-like特征最早是由Papageorgiou等应用于人脸表示,Viola和Jones在此基础上,使用3种类型4种形式的特征. Haar特征分为三类:边缘特征.线性 ...
- Linux之NFS网络文件系统
NFS(Network File System)即网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络资源共享.在NFS的应用中,本地NFS的客户端应用可 ...
- js初识
01-Javascript简介 Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) ...
- flink学习笔记-各种Time
说明:本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKh ...
- P2617 Dynamic Rankings 动态主席树
\(\color{#0066ff}{ 题目描述 }\) 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i ...
- 状压DP【洛谷P1896】 [SCOI2005]互不侵犯
P1896 [SCOI2005]互不侵犯 题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子 ...
- DataSet强类型、TableAdapter的使用
简答使用可以看https://www.cnblogs.com/namejr/p/10411920.html中的"先来简单介绍dataset和datatable" DataSet强类 ...
- Codeforce-A-Two distinct points(暴力)
output standard output You are given two segments [l1;r1][l1;r1] and [l2;r2][l2;r2] on the xx-axis. ...
- 10-排序6 Sort with Swap(0, i) (25 分)
Given any permutation of the numbers {0, 1, 2,..., N−1}, it is easy to sort them in increasing order ...
- echarts图调用多个接口
html: <div id="sentimentMain1" style="width:960px;height:500px;margin:20px auto;&q ...