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



    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实现单点登录的正确打开方式。

  • 相关阅读:
    flex设置成1和auto有什么区别
    在SUBLIME TEXT中安装SUBLIMELINTER进行JS&CSS代码校验
    gulp教程之gulp-less
    sublime注释插件与javascript注释规范
    移动端尺寸基础知识
    webpack入门教程
    IO中同步、异步与阻塞、非阻塞的区别
    Node.js的线程和进程
    Cocos2d-x 3.0中 物理碰撞检測中onContactBegin回调函数不响应问题
    hdu 1789 Doing Homework again 贪心
  • 原文地址:https://www.cnblogs.com/askmiw/p/11229437.html
Copyright © 2020-2023  润新知