环境:centos7,Java1.8+,一个Nginx,两个Tomcat,一个Redis。

关于共享session的问题大家都应该知道了,传统的部署项目,两个相同的项目部署到不同的服务器上,Nginx负载均衡后会导致用户在A上登陆了,经过负载均衡后,在B上要重新登录,因为A上有相关session信息,而B没有。这种情况也称为“有状态”服务。而“无状态”服务则是:在一个公共的地方存储session,每次访问都会统一到这个地方来拿。

为了方便我只用了一台linux虚拟机。

如果你使用了Shiro权限管理呢,他的好处之一就是会话管理,由Shiro管理Session,而不是Tomcat。听说都在用Spring-Session,实际上它和shiro一样,请看web.xml里面的配置

  1. <!-- spring-session Filter
  2. <filter>
  3. <filter-name>springSessionRepositoryFilter</filter-name>
  4. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  5. </filter>
  6. <filter-mapping>
  7. <filter-name>springSessionRepositoryFilter</filter-name>
  8. <url-pattern>/*</url-pattern>
  9. </filter-mapping>
  10. -->
  11.  
  12. <!-- Shiro Filter is defined in the spring application context: -->
  13. <filter>
  14. <filter-name>shiroFilter</filter-name>
  15. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  16. <init-param>
  17. <param-name>targetFilterLifecycle</param-name>
  18. <param-value>true</param-value>
  19. </init-param>
  20. </filter>
  21.  
  22. <filter-mapping>
  23. <filter-name>shiroFilter</filter-name>
  24. <url-pattern>/*</url-pattern>
  25. <dispatcher>REQUEST</dispatcher>
  26. <dispatcher>FORWARD</dispatcher>
  27. <dispatcher>INCLUDE</dispatcher>
  28. <dispatcher>ERROR</dispatcher>
  29. </filter-mapping>

不难看出,这两个都是基于:org.springframework.web.filter.DelegatingFilterProxy

下面开始正题。

使用Shiro需要继承AbstractSessionDAO

  1. package com.internetsaying.auth.session;
  2.  
  3. import java.io.Serializable;
  4. import java.util.Collection;
  5. import java.util.List;
  6.  
  7. import org.apache.shiro.session.Session;
  8. import org.apache.shiro.session.UnknownSessionException;
  9. import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.stereotype.Component;
  12.  
  13. import com.internetsaying.auth.redis.RedisManager;
  14.  
  15. @Component
  16. public class MySessionDao extends AbstractSessionDAO {
  17.  
  18. @Autowired
  19. private RedisManager redisManager;
  20.  
  21. @Override
  22. public void delete(Session session) {
  23. if(session == null || session.getId() == null){
  24. System.out.println("Session is null");
  25. return;
  26. }
  27. redisManager.hdelete(session.getId().toString());
  28. }
  29.  
  30. @Override
  31. public Collection<Session> getActiveSessions() {
  32. List<Session> list = redisManager.hmget();
  33. return list;
  34. }
  35.  
  36. @Override
  37. public void update(Session session) throws UnknownSessionException {
  38. if(session == null || session.getId() == null){
  39. System.out.println("Session is null");
  40. return;
  41. }
  42. Serializable sessionId = session.getId();
  43. redisManager.hadd(sessionId.toString(), session);
  44. }
  45.  
  46. @Override
  47. protected Serializable doCreate(Session session) {
  48. Serializable sessionId = generateSessionId(session);
  49. assignSessionId(session, sessionId);
  50. //添加进redis
  51. redisManager.hadd(sessionId.toString(), session);
  52.  
  53. return sessionId;
  54. }
  55.  
  56. @Override
  57. protected Session doReadSession(Serializable sessionId) {
  58. return redisManager.hget(sessionId.toString());
  59. }
  60.  
  61. }

下面是RedisManager的代码

  1. package com.internetsaying.auth.redis;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. import org.apache.shiro.session.Session;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.data.redis.core.RedisTemplate;
  9. import org.springframework.stereotype.Component;
  10.  
  11. @Component
  12. public class RedisManager {
  13.  
  14. @Autowired
  15. private RedisTemplate<String, Session> redisTemplate;
  16.  
  17. private static final String KEY = "shareSessionMap";
  18.  
  19. public void hadd(String sessionId, byte[] bytes){
  20. redisTemplate.boundHashOps(KEY).put(sessionId, bytes);
  21. }
  22. public void hadd(String sessionId, Session session){
  23. redisTemplate.boundHashOps(KEY).put(sessionId, session);
  24. }
  25.  
  26. public void hdelete(String sessionId){
  27. redisTemplate.boundHashOps(KEY).delete(sessionId);
  28. }
  29.  
  30. public Session hget(String sessionId){
  31. return (Session) redisTemplate.boundHashOps(KEY).get(sessionId);
  32. }
  33.  
  34. public List<Session> hmget(){
  35. List<Session> list = new ArrayList<>();
  36.  
  37. List<Object> values = redisTemplate.boundHashOps(KEY).values();
  38. for (Object object : values) {
  39. list.add((Session) object);
  40. }
  41. return list;
  42. }
  43. }

配置文件:shiro和redis部分(只是与共享session相关的代码)

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:core="http://activemq.apache.org/schema/core"
  6. xmlns:redis="http://www.springframework.org/schema/redis"
  7. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
  9. http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core
  10. http://www.springframework.org/schema/redis http://www.springframework.org/schema/redis/spring-redis-1.0.xsd">
  11.  
  12. <!-- SecurityManager -->
  13. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
  14. <!-- session管理 -->
  15. <property name="sessionManager" ref="sessionManager"></property>
  16. </bean>
  17. <!-- redis操作 -->
  18. <bean id="redisManager" class="com.internetsaying.auth.redis.RedisManager"></bean>
  19. <!-- Session ID 生成器 -->
  20. <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"></bean>
  21. <!-- SessionDao实现类 -->
  22. <bean id="sessionDAO" class="com.internetsaying.auth.session.MySessionDao">
  23. <property name="sessionIdGenerator" ref="sessionIdGenerator"></property>
  24. </bean>
  25. <!-- session管理 -->
  26. <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
  27. <property name="globalSessionTimeout" value="1800000"></property>
  28. <property name="deleteInvalidSessions" value="true"></property>
  29. <property name="sessionDAO" ref="sessionDAO"></property>
  30. <!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
  31. <property name="sessionIdCookie" ref="sharesession" />
  32. </bean>
  33. <!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
  34. <bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie">
  35. <!-- cookie的name,对应的默认是 JSESSIONID -->
  36. <constructor-arg name="name" value="SHAREJSESSIONID" />
  37. <!-- jsessionId的path为 / 用于多个系统共享jsessionId -->
  38. <property name="path" value="/" />
  39. <property name="httpOnly" value="true"/>
  40. </bean>
  41.  
  42. <!-- 以下是Redis -->
  43. <context:property-placeholder location="classpath:redis.properties"/>
  44. <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
  45. <property name="maxIdle" value="${redis.maxIdle}"></property>
  46. <property name="maxTotal" value="${redis.maxTotal}"></property>
  47. <property name="maxWaitMillis" value="${redis.maxWaitMillis}"></property>
  48. <property name="testOnBorrow" value="${redis.testOnBorrow}"></property>
  49. </bean>
  50.  
  51. <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
  52. <property name="usePool" value="${redis.pooled}"></property>
  53. <property name="hostName" value="${redis.host}"></property>
  54. <property name="port" value="${redis.port}"></property>
  55. <property name="poolConfig" ref="jedisPoolConfig"></property>
  56. </bean>
  57. <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
  58. <property name="connectionFactory" ref="jedisConnectionFactory"></property>
  59. <property name="keySerializer">
  60. <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
  61. </property>
  62. <!-- 解决读取int类型value值报错的问题 -->
  63. <property name="valueSerializer">
  64. <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
  65. </property>
  66. <property name="hashKeySerializer">
  67. <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
  68. </property>
  69. </bean>
  70.  
  71. </beans>

配置文件:redis.properties

  1. #Redis settings
  2.  
  3. redis.host=127.0.0.1
  4. redis.port=6379
  5. #redis.pass=
  6. redis.maxIdle=30
  7. redis.maxTotal=100
  8. redis.maxWaitMillis=1000
  9. redis.testOnBorrow=true
  10. redis.pooled=true

执行流程

说明:由于做的是分布式项目,不便贴上全部代码,如遇问题可联系我:3110320051.

我有个完整的小栗子

部署

关于Nginx做负载均衡可参考我上一篇文章。

这里将项目打包后,分别上传到两个Tomcat,启动。当访问时。【页面过于简单,仅供测试】

点击登录既完成Shiro的认证授权,跳转到可访问页面。

刷新

注意cookie的Value

现在我们看一下redis存储的:

  1. [root@localhost local]# ./bin/redis-cli
  2. 127.0.0.1:6379> keys *
  3. 1) "shareSessionMap"
  4. 127.0.0.1:6379> HKEYS shareSessionMap
  5. 1) "a511c5c4-9f61-4c24-aad2-b551f8053ebf"

所以:每次服务器都是去redis里面去拿的session,登录A后,切换到B不需要重新登录。

Redis+Shiro+Spring-data-redis,共享Session的更多相关文章

  1. Redis与Spring Data Redis

    1.Redis概述 1.1介绍 官网:https://redis.io/ Redis是一个开源的使用ANSIC语言编写.支持网络.可基于内存 亦可持久化的日志型.Key-Value型的高性能数据库. ...

  2. Redis(八):spring data redis 理解

    前言 Spring Data Redis project,应用了Spring概念来开发使用键值形式的数据存储的解决方案.我们(官方)提供了一个 "template" ,这是一个高级 ...

  3. Redis客户端 Spring Data Redis(未完)

    官网:http://projects.spring.io/spring-data-redis/ 1.0  参考之前的一片文章:Gradle入门实战(Windows版) 构建java applicati ...

  4. Spring Data Redis整体介绍 (一)

    为什么使用Spring Data Redis 首先Spring Data Redis 是Spring 框架提供的用于操作Redis的客户端. Spring框架是一个全栈Java程序框架,通过DI.AO ...

  5. spring boot通过Spring Data Redis集成redis

    在spring boot中,默认集成的redis是Spring Data Redis,Spring Data Redis针对redis提供了非常方便的操作模版RedisTemplate idea中新建 ...

  6. Spring Data Redis 让 NoSQL 快如闪电(2)

    [编者按]本文作者为 Xinyu Liu,文章的第一部分重点概述了 Redis 方方面面的特性.在第二部分,将介绍详细的用例.文章系国内 ITOM 管理平台 OneAPM 编译呈现. 把 Redis ...

  7. Spring Data Redis学习

    本文是从为知笔记上复制过来的,懒得调整格式了,为知笔记版本是带格式的,内容也比这里全.点这里 为知笔记版本 Spring Data Redis 学习 Version 1.8.4.Release 前言 ...

  8. Spring Boot使用Spring Data Redis操作Redis(单机/集群)

    说明:Spring Boot简化了Spring Data Redis的引入,只要引入spring-boot-starter-data-redis之后会自动下载相应的Spring Data Redis和 ...

  9. 使用Spring Data Redis操作Redis(集群版)

    说明:请注意Spring Data Redis的版本以及Spring的版本!最新版本的Spring Data Redis已经去除Jedis的依赖包,需要自行引入,这个是个坑点.并且会与一些低版本的Sp ...

  10. 使用Spring Data Redis操作Redis(单机版)

    说明:请注意Spring Data Redis的版本以及Spring的版本!最新版本的Spring Data Redis已经去除Jedis的依赖包,需要自行引入,这个是个坑点.并且会与一些低版本的Sp ...

随机推荐

  1. better-scroll项目中遇到的问题

    1.在项目中发现个问题,用better-scroll实现的轮播图和页面滚动条俩个效果一起出现的时候,当鼠标或手指放在轮播图位置的时候,上下滚动的时候,页面滚动条不动 发现最新的版本就会出这个问题,就是 ...

  2. js的页面传值cookie.session

    jquery的cookie: 读取所有的cookie: document.cookie: 读取单个cookie:$.cookie('cookiename'); 新增cookie: $.cookie(' ...

  3. easyui combogrid下拉表格的分页/按键/动态搜索

    作者:xfl4629712  <  easyui combogrid下拉表格的分页/按键/动态搜索  > 需求: 1.下拉框下拉时出现表格: 2.表格带分页功能: 3.可以使用向上键.向下 ...

  4. Confluence 6 复杂授权或性能问题

    提交一个 服务器请求(support request) 然后在你的服务请求中同时提供下面的信息. Confluence 服务器 登录 Confluence 然后访问管理员控制台. 将 系统信息(Sys ...

  5. Confluence 6 连接到外部用户目录服务器的问题分析

    在有关外部目录服务器配置页面中有一个测试配置(Test Settings)按钮.这个功能将会帮助你分析你的用户管理在 Active Directory 和其他 LDAP 服务器中出现的问题. 希望对你 ...

  6. centos7查看yum安装的软件及路径

    rpm -qa 查看所有已安装软件名称 rpm -ql 软件名 显示软件的安装路径

  7. ionic3 打包报错[ERROR] An error occurred while running cordova prepare (exit code 1):

    解决办法:删除并重新添加平台以使用以下命令解决问题: cordova platform rm ios cordova platform add ios 如果执行 ionic cordova build ...

  8. Redis创建集群报错

    Redis创建集群报错: 1:任何一个集群节点中都不能存在数据,如果有备份一下删除掉aof文件或rdb文件 2: nodes-集群端口.conf 文件存的会有报错记录,所以该文件也要删除

  9. python 垃圾回收

    # 垃圾回收 # 小整数对象池 # a = 100# python对小整数的定义是[-5,257],这些证书对象是提前创建好的,不会被垃圾回收,再一个python的程序中,所有位于这个范围内的正式使用 ...

  10. NodeJs——router报错原因

    rout.js var http = require('http'); var url = require('url'); var router = require('./models/router. ...