使用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實現單點登陸的正確打開方式。