基於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

相關文章
相關標籤/搜索