为实现Web应用的分布式集群部署,要解决登录session的统一。本文利用shiro做权限控制,redis做session存储,结合spring boot快速配置实现session共享。

  1、引入相关依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-redis</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.apache.shiro</groupId>
  7. <artifactId>shiro-spring</artifactId>
  8. <version>1.3.2</version>
  9. </dependency>

  2、Redis相关

  2.1.redis配置

  1.   spring.redis.host=localhost
  2.   spring.redis.port=6379
  3.   spring.redis.password=

  2.2.redis缓存的对象必须序列化,通用序列化 

  1. import org.springframework.core.convert.converter.Converter;
  2. import org.springframework.core.serializer.support.DeserializingConverter;
  3. import org.springframework.core.serializer.support.SerializingConverter;
  4. import org.springframework.data.redis.serializer.RedisSerializer;
  5. import org.springframework.data.redis.serializer.SerializationException;
  6.  
  7. /**
  8. * redis序列化对象
  9. */
  10. public class RedisObjectSerializer implements RedisSerializer<Object> {
  11. private Converter<Object, byte[]> serializer = new SerializingConverter();
  12. private Converter<byte[], Object> deserializer = new DeserializingConverter();
  13. static final byte[] EMPTY_ARRAY = new byte[0];
  14.  
  15. public Object deserialize(byte[] bytes) {
  16. if (isEmpty(bytes)) {
  17. return null;
  18. }
  19. try {
  20. return deserializer.convert(bytes);
  21. } catch (Exception ex) {
  22. throw new SerializationException("Cannot deserialize", ex);
  23. }
  24. }
  25.  
  26. public byte[] serialize(Object object) {
  27. if (object == null) {
  28. return EMPTY_ARRAY;
  29. }
  30. try {
  31. return serializer.convert(object);
  32. } catch (Exception ex) {
  33. return EMPTY_ARRAY;
  34. }
  35. }
  36.  
  37. private boolean isEmpty(byte[] data) {
  38. return (data == null || data.length == 0);
  39. }
  40. }

  2.3 RedisTemplate 配置

  1. import org.springframework.cache.CacheManager;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.data.redis.cache.RedisCacheManager;
  5. import org.springframework.data.redis.connection.RedisConnectionFactory;
  6. import org.springframework.data.redis.core.RedisTemplate;
  7. import org.springframework.data.redis.serializer.StringRedisSerializer;
  8.  
  9. /**
  10. * redis 配置
  11. */
  12. @Configuration
  13. public class RedisConfig {
  14.  
  15. @Bean
  16. public CacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
  17. RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
  18. cacheManager.setDefaultExpiration(1800);
  19. return cacheManager;
  20. }
  21.  
  22. @Bean
  23. public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
  24. RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
  25. template.setConnectionFactory(factory);
  26. template.setKeySerializer(new StringRedisSerializer());
  27. template.setValueSerializer(new RedisObjectSerializer());
  28. return template;
  29. }
  30. }

  3.Redis实现shiro的SessionDao存取session

  1. import java.io.Serializable;
  2. import java.util.concurrent.TimeUnit;
  3.  
  4. import javax.annotation.Resource;
  5.  
  6. import org.apache.shiro.session.Session;
  7. import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;
  10. import org.springframework.data.redis.core.RedisTemplate;
  11. import org.springframework.stereotype.Component;
  12.  
  13. /**
  14. * redis实现共享session
  15. */
  16. @Component
  17. public class RedisSessionDAO extends EnterpriseCacheSessionDAO {
  18.  
  19. private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
  20.  
  21. // session 在redis过期时间是30分钟30*60
  22. private static int expireTime = 1800;
  23.  
  24. private static String prefix = "weiyou-shiro-session:";
  25.  
  26. @Resource
  27. private RedisTemplate<String, Object> redisTemplate;
  28.  
  29. // 创建session,保存到数据库
  30. @Override
  31. protected Serializable doCreate(Session session) {
  32. Serializable sessionId = super.doCreate(session);
  33. logger.debug("创建session:{}", session.getId());
  34. redisTemplate.opsForValue().set(prefix + sessionId.toString(), session);
  35. return sessionId;
  36. }
  37.  
  38. // 获取session
  39. @Override
  40. protected Session doReadSession(Serializable sessionId) {
  41. logger.debug("获取session:{}", sessionId);
  42. // 先从缓存中获取session,如果没有再去数据库中获取
  43. Session session = super.doReadSession(sessionId);
  44. if (session == null) {
  45. session = (Session) redisTemplate.opsForValue().get(prefix + sessionId.toString());
  46. }
  47. return session;
  48. }
  49.  
  50. // 更新session的最后一次访问时间
  51. @Override
  52. protected void doUpdate(Session session) {
  53. super.doUpdate(session);
  54. logger.debug("获取session:{}", session.getId());
  55. String key = prefix + session.getId().toString();
  56. if (!redisTemplate.hasKey(key)) {
  57. redisTemplate.opsForValue().set(key, session);
  58. }
  59. redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
  60. }
  61.  
  62. // 删除session
  63. @Override
  64. protected void doDelete(Session session) {
  65. logger.debug("删除session:{}", session.getId());
  66. super.doDelete(session);
  67. redisTemplate.delete(prefix + session.getId().toString());
  68. }
  69. }

  4.实现cache共享

  1. import java.util.ArrayList;
  2. import java.util.Collection;
  3. import java.util.List;
  4. import java.util.Set;
  5. import java.util.concurrent.TimeUnit;
  6.  
  7. import org.apache.shiro.cache.Cache;
  8. import org.apache.shiro.cache.CacheException;
  9. import org.springframework.data.redis.core.RedisTemplate;
  10.  
  11. @SuppressWarnings("unchecked")
  12. public class ShiroCache<K, V> implements Cache<K, V> {
  13.  
  14. private static final String REDIS_SHIRO_CACHE = "weiyou-shiro-cache:";
  15. private String cacheKey;
  16. private RedisTemplate<K, V> redisTemplate;
  17. private long globExpire = 30;
  18.  
  19. @SuppressWarnings("rawtypes")
  20. public ShiroCache(String name, RedisTemplate client) {
  21. this.cacheKey = REDIS_SHIRO_CACHE + name + ":";
  22. this.redisTemplate = client;
  23. }
  24.  
  25. @Override
  26. public V get(K key) throws CacheException {
  27. redisTemplate.boundValueOps(getCacheKey(key)).expire(globExpire, TimeUnit.MINUTES);
  28. return redisTemplate.boundValueOps(getCacheKey(key)).get();
  29. }
  30.  
  31. @Override
  32. public V put(K key, V value) throws CacheException {
  33. V old = get(key);
  34. redisTemplate.boundValueOps(getCacheKey(key)).set(value);
  35. return old;
  36. }
  37.  
  38. @Override
  39. public V remove(K key) throws CacheException {
  40. V old = get(key);
  41. redisTemplate.delete(getCacheKey(key));
  42. return old;
  43. }
  44.  
  45. @Override
  46. public void clear() throws CacheException {
  47. redisTemplate.delete(keys());
  48. }
  49.  
  50. @Override
  51. public int size() {
  52. return keys().size();
  53. }
  54.  
  55. @Override
  56. public Set<K> keys() {
  57. return redisTemplate.keys(getCacheKey("*"));
  58. }
  59.  
  60. @Override
  61. public Collection<V> values() {
  62. Set<K> set = keys();
  63. List<V> list = new ArrayList<>();
  64. for (K s : set) {
  65. list.add(get(s));
  66. }
  67. return list;
  68. }
  69.  
  70. private K getCacheKey(Object k) {
  71. return (K) (this.cacheKey + k);
  72. }
  73. }

  实现shiro 的CacheManager

  1. import javax.annotation.Resource;
  2.  
  3. import org.apache.shiro.cache.Cache;
  4. import org.apache.shiro.cache.CacheException;
  5. import org.apache.shiro.cache.CacheManager;
  6. import org.springframework.data.redis.core.RedisTemplate;
  7.  
  8. public class RedisCacheManager implements CacheManager {
  9.  
  10. @Resource
  11. private RedisTemplate<String, Object> redisTemplate;
  12.  
  13. @Override
  14. public <K, V> Cache<K, V> getCache(String name) throws CacheException {
  15. return new ShiroCache<K, V>(name, redisTemplate);
  16. }
  17.  
  18. public RedisTemplate<String, Object> getRedisTemplate() {
  19. return redisTemplate;
  20. }
  21.  
  22. public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
  23. this.redisTemplate = redisTemplate;
  24. }
  25.  
  26. }

5.配置

  

  1. import java.util.HashMap;
  2. import java.util.Map;
  3.  
  4. import javax.annotation.Resource;
  5.  
  6. import org.apache.shiro.session.mgt.SessionManager;
  7. import org.apache.shiro.spring.LifecycleBeanPostProcessor;
  8. import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
  9. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  10. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  11. import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
  12. import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
  13. import org.springframework.context.annotation.Bean;
  14. import org.springframework.context.annotation.Configuration;
  15.  
  16. /**
  17. *
  18. * @author April.Chen
  19. */
  20. //@Configuration
  21. public class ShiroConfig {
  22.  
  23. @Resource
  24. private RedisSessionDAO sessionDAO;
  25.  
  26. @Bean
  27. public UserRealm getUserRealm() {
  28. return new UserRealm();
  29. }
  30.  
  31. @Bean
  32. public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
  33. return new LifecycleBeanPostProcessor();
  34. }
  35.  
  36. @Bean
  37. public RedisCacheManager redisCacheManager() {
  38. return new RedisCacheManager();
  39. }
  40.  
  41. @Bean
  42. public SessionManager sessionManager() {
  43. DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
  44. sessionManager.setSessionDAO(sessionDAO);
  45. sessionManager.setGlobalSessionTimeout(1800);
  46. sessionManager.setCacheManager(redisCacheManager());
  47. return sessionManager;
  48. }
  49.  
  50. @Bean
  51. public DefaultWebSecurityManager securityManager() {
  52. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  53. securityManager.setSessionManager(sessionManager());
  54. securityManager.setCacheManager(redisCacheManager());
  55. return securityManager;
  56. }
  57.  
  58. @Bean
  59. public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
  60. AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
  61. aasa.setSecurityManager(securityManager());
  62. return new AuthorizationAttributeSourceAdvisor();
  63. }
  64.  
  65. @Bean
  66. public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
  67. DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
  68. daap.setProxyTargetClass(true);
  69. return daap;
  70. }
  71.  
  72. @Bean
  73. public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
  74. Map<String, String> filterChainDefinitionMap = new HashMap<>();
  75. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  76. shiroFilterFactoryBean.setSecurityManager(securityManager());
  77. shiroFilterFactoryBean.setLoginUrl("/login");
  78. shiroFilterFactoryBean.setSuccessUrl("/index");
  79. filterChainDefinitionMap.put("/sa/**", "authc");
  80. filterChainDefinitionMap.put("/**", "anon");
  81. shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
  82. return shiroFilterFactoryBean;
  83. }
  84. }

Spring Boot + Redis 实现Shiro集群的更多相关文章

  1. Spring Boot集成Hazelcast实现集群与分布式内存缓存

    Hazelcast是Hazelcast公司开源的一款分布式内存数据库产品,提供弹性可扩展.高性能的分布式内存计算.并通过提供诸如Map,Queue,ExecutorService,Lock和JCach ...

  2. Spring Boot项目配置RabbitMQ集群

    //具体参看了配置的源码 org.springframework.boot.autoconfigure.amqp.RabbitProperties //RabbitMQ单机 spring:   rab ...

  3. spring + spring-data-redist + Redis 单机、集群(cluster模式,哨兵模式)

    一.单机redis配置 1. 配置redis连接池 <bean id="jedisPoolConfig" class="redis.clients.jedis.Je ...

  4. Apache shiro集群实现 (七)分布式集群系统下---cache共享

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  5. Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  6. Redis 高可用集群

    Redis 高可用集群 Redis 的集群主从模型是一种高可用的集群架构.本章主要内容有:高可用集群的搭建,Jedis连接集群,新增集群节点,删除集群节点,其他配置补充说明. 高可用集群搭建 集群(c ...

  7. Apache shiro集群实现 (八) web集群时session同步的3种方法

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  8. Apache shiro集群实现 (五)分布式集群系统下的高可用session解决方案

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  9. Apache shiro集群实现 (四)shiro授权(Authentication)--访问控制

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

随机推荐

  1. jQuery回车触发事件

    举例: 需求:要求回车触发下一步 Html部分 <div style="margin-top: 25px;"> <a href="#" cla ...

  2. ThinkPHP3.2.3完整版创建前后台入口文件 http://jingyan.baidu.com/article/7e4409533fc1092fc1e2ef53.html

    ThinkPHP3.2.3完整版创建前后台入口文件   1 2 3 4 5 6 7 分步阅读 ThinkPHP是为了简化企业级应用开发和敏捷WEB应用开发而诞生的优秀的国产php框架,值得我们去探索学 ...

  3. String s String s=null和String s="a"区别

    原文链接:https://www.cnblogs.com/ipetergo/p/6826909.htmlString s;和String s=null;和String s="a"; ...

  4. Zookeeper基础使用

    部署和运行 脚本 ZooKeeper的bin目录下的脚本见下表 脚本 说明 zkCleanup 清理ZooKeeper历史数据,包括事务日志文件和快照数据文件 zkCli ZooKeeper的一个简易 ...

  5. atcoder 2643 切比雪夫最小生成树

    There are N towns on a plane. The i-th town is located at the coordinates (xi,yi). There may be more ...

  6. [国家集训队]happiness 最小割 BZOJ 2127

    题目描述 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文 ...

  7. 【Cracking the Code Interview(5th edition)】一、数组与字符串(C++)

    1.1 实现一个算法,确定一个字符串的所有字符是否全都不同.不允许使用额外的数据结构. 解答:这里假定字符集为ASCII码,可以与面试官沟通确认字符串使用的字符集.由于字符集是有限的,建立一个数组模拟 ...

  8. 钉钉jsapi免登获取code中,出现对应企业没有某域名微应用

    在使用jsapi中.出现 {"errorMessage":"对应企业没有某域名微应用",:"errorCode":"3" ...

  9. Unity 动画系统目录 之 Animation

    返回 Unity 动画系统目录 官方文档 Animation:https://docs.unity3d.com/ScriptReference/Animation.html Animator:http ...

  10. CF D. Fair(思维+DFS)

    http://codeforces.com/contest/987/problem/D 题目大概: 给出一个n个城镇m条边的图,给出每个城镇拥有的特产(可能多个城镇有相同特产).有k种不同特产. 要求 ...