使用Redis来实现Session共享,其实网上已经有不少例子了,这是确保在集群部署中最典型的redis使用场景。在SpringBoot项目中,其实能够一行运行代码都不用写,只须要简单添加添加依赖和一行注解就能够实现(固然配置信息仍是须要的)。
而后简单地把该项目部署到不一样的tomcat下,好比不一样的端口(A、B),但项目访问路径是相同的。此时在A中使用set方法,而后在B中使用get方法,就能够发现B中能够获取A中设置的内容。
但若是就把这样的一个项目在多个tomcat中的部署说实现了单点登陆,那就不对了。
所谓单点登陆是指在不一样的项目中,只须要任何一个项目登陆了,其余项目不须要登陆。
一样是上面的例子,咱们把set和get两个方法分别放到两个项目(set、get)中,而且以集群方式把两个项目都部署到服务器A和B中,而后分别访问A服务器的set和B服务器的get,你就会发现彻底得不到你想要的结果。
@SpringBootApplication@EnableRedisHttpSession@RestControllerpublic 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方法拆分为两个项目。
@SpringBootApplication@EnableRedisHttpSession@RestControllerpublic 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; }}
@SpringBootApplication@EnableRedisHttpSession@RestControllerpublic 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值了。
@Configurationpublic class CookieConfig { @Bean public static DefaultCookieSerializer defaultCookieSerializer() { DefaultCookieSerializer serializer = new DefaultCookieSerializer(); serializer.setCookiePath("/"); //serializer.setDomainName("xxx.com"); //若是使用域名访问,建议对这一句进行设置 return serializer; }}
以上才是正直的redis实现单点登陆的正确打开方式。