基于SpringBoot+Redis的Session共享与单点登录

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: title: 基于SpringBoot+Redis的Session共享与单点登录date: 2019-07-23 02:55:52categories:架构author: mrzhoutags:SpringBootredissession单点登录基于SpringBoot+Redis的Session共享与单点登录前言使用Redis来实现Session共享,其实网上已经有很多例子了,这是确保在集群部署中最典型的redis使用场景。

title: 基于SpringBoot+Redis的Session共享与单点登录
date: 2019-07-23 02:55:52
categories:

架构
author: mrzhou
tags:
SpringBoot
redis
session
单点登录
基于SpringBoot+Redis的Session共享与单点登录
前言
使用Redis来实现Session共享,其实网上已经有很多例子了,这是确保在集群部署中最典型的redis使用场景。在SpringBoot项目中,其实可以一行运行代码都不用写,只需要简单添加添加依赖和一行注解就可以实现(当然配置信息还是需要的)。
然后简单地把该项目部署到不同的tomcat下,比如不同的端口(A、B),但项目访问路径是相同的。此时在A中使用set方法,然后在B中使用get方法,就可以发现B中可以获取A中设置的内容。

但如果就把这样的一个项目在多个tomcat中的部署说实现了单点登录,那就不对了。

所谓单点登录是指在不同的项目中,只需要任何一个项目登录了,其他项目不需要登录。

同样是上面的例子,我们把set和get两个方法分别放到两个项目(set、get)中,并且以集群方式把两个项目都部署到服务器A和B中,然后分别访问A服务器的set和B服务器的get,你就会发现完全得不到你想要的结果。

同一项目中的set/get
依赖添加就不说了,直接使用最简单的方式

@SpringBootApplication
@EnableRedisHttpSession
@RestController
public class SessionShareApplication {

public static void main(String[] args) {
    SpringApplication.run(SessionShareApplication.class, args);
}

@Autowired
HttpSession session;
@Autowired
HttpServletRequest req;

@GetMapping("/set")
public Object set() {
    session.setAttribute("state", "state was setted.");
    Map<String, Object> map = new TreeMap<>();
    map.put("msg", session.getAttribute("state"));
    map.put("serverPort", req.getLocalPort());
    return map;
}
@GetMapping("/get")
public Object get() {
    Map<String, Object> map = new TreeMap<>();
    map.put("msg", session.getAttribute("state"));
    map.put("serverPort", req.getLocalPort());
    return map;
}

}
将该项目打war包,分别部署在tomcatA(端口8080),tomcatB(端口8081),然后通过tomcatA/set 方法设置session,再使用 tomcatB/get 方法即可获得session的值。但这只是实现了同一项目session的共享。并不是单点登录。

为了验证,我们不仿将set/get方法拆分为两个项目。

拆分set/get为两个项目
get项目
@SpringBootApplication
@EnableRedisHttpSession
@RestController
public class SetApplication {

public static void main(String[] args) {
    SpringApplication.run(SetApplication.class, args);
}

@Autowired
HttpSession session;
@Autowired
HttpServletRequest req;

@GetMapping("/")
public Object set() {
    session.setAttribute("state", "state was setted.");
    Map<String, Object> map = new TreeMap<>();
    map.put("msg", session.getAttribute("state"));
    map.put("serverPort", req.getLocalPort());
    return map;
}

}
将该项目打包为set.war

set项目
@SpringBootApplication
@EnableRedisHttpSession
@RestController
public class GetApplication {

public static void main(String[] args) {
    SpringApplication.run(GetApplication.class, args);
}

@Autowired
HttpSession session;
@Autowired
HttpServletRequest req;

@GetMapping("/")
public Object get() {
    Map<String, Object> map = new TreeMap<>();
    map.put("msg", session.getAttribute("state"));
    map.put("serverPort", req.getLocalPort());
    return map;
}

}
将该项目打包为get.war
再分别将set.war,get.war部署在tomcatA和tomcatB,再通过 tomcatA/set 设置session内容, 然后通过 tomcatB/get 就发现无法获得session的值。

问题分析
尽管我们使用的路径都是一样的,但其实是两个项目,与前面的一个项目是完全不同的,问题就在于 session和cookie在默认情况下是与项目路径相关的,在同一个项目的情况下两个方法所需要的cookie依赖的项目路径是相同的,所以获取session的值就没有问题,但在后一种情况下,cookie的路径是分别属于不同的项目的,所以第二个项目就无法获得第一个项目中设置的session内容了。

解决方法
解决方法在springboot项目中其实也非常简单。既然cookie路径发生了变化,那我们让它配置为相同的路径就解决了。
在每个子项目中都添加一个配置类或者直接设置cookie的路径,如果有域名还可以设置域名的限制,比如 set.xxx.com 与 get.xxx.com 这种情况与我们就需要设置cookie的域名为 xxx.com,以确保无法在哪个项目下都能够获取 xxx.com 这个域名下的cookie值。这样就确保能够正常获得共享的session值了。

@Configuration
public class CookieConfig {

@Bean
public static DefaultCookieSerializer defaultCookieSerializer() {
    DefaultCookieSerializer serializer = new DefaultCookieSerializer();
    serializer.setCookiePath("/");
    //serializer.setDomainName("xxx.com"); //如果使用域名访问,建议对这一句进行设置    
    return serializer;
}

}
以上才是正直的redis实现单点登录的正确打开方式。
原文地址https://www.cnblogs.com/askmiw/p/11229437.html

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
14天前
|
NoSQL Java Redis
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
SpringBoot集成Redis解决表单重复提交接口幂等(亲测可用)
47 0
|
27天前
|
消息中间件 NoSQL Java
springboot redis 实现消息队列
springboot redis 实现消息队列
34 1
|
19天前
|
NoSQL Java Redis
SpringBoot集成Redis
SpringBoot集成Redis
153 0
|
15天前
|
NoSQL Java Redis
SpringBoot集成Redis
SpringBoot集成Redis
39 1
|
25天前
|
缓存 NoSQL Java
springboot中集成redis,二次封装成工具类
springboot中集成redis,二次封装成工具类
155 0
|
28天前
|
缓存 NoSQL Java
spring cache整合redis实现springboot项目中的缓存功能
spring cache整合redis实现springboot项目中的缓存功能
44 1
|
1月前
|
监控 NoSQL Java
Spring Boot集成Redis启动失败【Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.G】
Spring Boot集成Redis启动失败【Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.G】
|
NoSQL Java 应用服务中间件
|
NoSQL Java 应用服务中间件
使用redis进行基于shiro的session集群共享
之前写过一篇nginx多tomcat负载均衡,主要记录了使用nginx对多个tomcat 进行负载均衡,其实进行负载均衡之前还有一个问题没有解决,那就是集群间的session共享,不然用户在登录网站之后session保存在tomcat A,但是下次访问的时候nginx分发到了tomcat B,这个时...
1117 0
|
NoSQL Java 应用服务中间件
使用redis进行基于shiro的session集群共享
之前写过一篇nginx多tomcat负载均衡,主要记录了使用nginx对多个tomcat 进行负载均衡,其实进行负载均衡之前还有一个问题没有解决,那就是集群间的session共享,不然用户在登录网站之后session保存在tomcat A,但是下次访问的时候nginx分发到了tomcat B,这个时...
1345 0