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

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

前言

使用Redis来实现Session共享,其实网上已经有不少例子了,这是确保在集群部署中最典型的redis使用场景。在SpringBoot项目中,其实能够一行运行代码都不用写,只须要简单添加添加依赖和一行注解就能够实现(固然配置信息仍是须要的)。 而后简单地把该项目部署到不一样的tomcat下,好比不一样的端口(A、B),但项目访问路径是相同的。此时在A中使用set方法,而后在B中使用get方法,就能够发现B中能够获取A中设置的内容。html

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

所谓单点登陆是指在不一样的项目中,只须要任何一个项目登陆了,其余项目不须要登陆。redis

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

同一项目中的set/get

依赖添加就不说了,直接使用最简单的方式tomcat

@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的共享。并非单点登陆。springboot

为了验证,咱们不仿将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.warcookie

  • 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

问题分析

尽管咱们使用的路径都是同样的,但实际上是两个项目,与前面的一个项目是彻底不一样的,问题就在于 session和cookie在默认状况下是与项目路径相关的,在同一个项目的状况下两个方法所须要的cookie依赖的项目路径是相同的,因此获取session的值就没有问题,但在后一种状况下,cookie的路径是分别属于不一样的项目的,因此第二个项目就没法得到第一个项目中设置的session内容了。app

解决方法

解决方法在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

相关文章
相关标签/搜索