日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
集群化部署,SpringSecurity要如何處理Session共享?

大家聊了 Spring Security 如何像 QQ 一樣,自動(dòng)踢掉已登錄用戶,但是前面我們是基于單體應(yīng)用的,如果我們的項(xiàng)目是集群化部署,這個(gè)問題該如何解決呢?

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)慶云免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了成百上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

今天我們就來看看集群化部署,Spring Security 要如何處理 session 并發(fā)。

1.集群會(huì)話方案

在傳統(tǒng)的單服務(wù)架構(gòu)中,一般來說,只有一個(gè)服務(wù)器,那么不存在 Session 共享問題,但是在分布式/集群項(xiàng)目中,Session 共享則是一個(gè)必須面對(duì)的問題,先看一個(gè)簡(jiǎn)單的架構(gòu)圖:

 

在這樣的架構(gòu)中,會(huì)出現(xiàn)一些單服務(wù)中不存在的問題,例如客戶端發(fā)起一個(gè)請(qǐng)求,這個(gè)請(qǐng)求到達(dá) Nginx 上之后,被 Nginx 轉(zhuǎn)發(fā)到 Tomcat A 上,然后在 Tomcat A 上往 session 中保存了一份數(shù)據(jù),下次又來一個(gè)請(qǐng)求,這個(gè)請(qǐng)求被轉(zhuǎn)發(fā)到 Tomcat B 上,此時(shí)再去 Session 中獲取數(shù)據(jù),發(fā)現(xiàn)沒有之前的數(shù)據(jù)。

1.1 session 共享

對(duì)于這一類問題的解決,目前比較主流的方案就是將各個(gè)服務(wù)之間需要共享的數(shù)據(jù),保存到一個(gè)公共的地方(主流方案就是 Redis):

 

當(dāng)所有 Tomcat 需要往 Session 中寫數(shù)據(jù)時(shí),都往 Redis 中寫,當(dāng)所有 Tomcat 需要讀數(shù)據(jù)時(shí),都從 Redis 中讀。這樣,不同的服務(wù)就可以使用相同的 Session 數(shù)據(jù)了。

這樣的方案,可以由開發(fā)者手動(dòng)實(shí)現(xiàn),即手動(dòng)往 Redis 中存儲(chǔ)數(shù)據(jù),手動(dòng)從 Redis 中讀取數(shù)據(jù),相當(dāng)于使用一些 Redis 客戶端工具來實(shí)現(xiàn)這樣的功能,毫無疑問,手動(dòng)實(shí)現(xiàn)工作量還是蠻大的。

一個(gè)簡(jiǎn)化的方案就是使用 Spring Session 來實(shí)現(xiàn)這一功能,Spring Session 就是使用 Spring 中的代理過濾器,將所有的 Session 操作攔截下來,自動(dòng)的將數(shù)據(jù) 同步到 Redis 中,或者自動(dòng)的從 Redis 中讀取數(shù)據(jù)。

對(duì)于開發(fā)者來說,所有關(guān)于 Session 同步的操作都是透明的,開發(fā)者使用 Spring Session,一旦配置完成后,具體的用法就像使用一個(gè)普通的 Session 一樣。

1.2 session 拷貝

session 拷貝就是不利用 redis,直接在各個(gè) Tomcat 之間進(jìn)行 session 數(shù)據(jù)拷貝,但是這種方式效率有點(diǎn)低,Tomcat A、B、C 中任意一個(gè)的 session 發(fā)生了變化,都需要拷貝到其他 Tomcat 上,如果集群中的服務(wù)器數(shù)量特別多的話,這種方式不僅效率低,還會(huì)有很嚴(yán)重的延遲。

所以這種方案一般作為了解即可。

1.3 粘滯會(huì)話

所謂的粘滯會(huì)話就是將相同 IP 發(fā)送來的請(qǐng)求,通過 Nginx 路由到同一個(gè) Tomcat 上去,這樣就不用進(jìn)行 session 共享與同步了。這是一個(gè)辦法,但是在一些極端情況下,可能會(huì)導(dǎo)致負(fù)載失衡(因?yàn)榇蟛糠智闆r下,都是很多人用同一個(gè)公網(wǎng) IP)。

所以,Session 共享就成為了這個(gè)問題目前主流的解決方案了。

2.Session共享

2.1 創(chuàng)建工程

首先 創(chuàng)建一個(gè) Spring Boot 工程,引入 Web、Spring Session、Spring Security 以及 Redis:

 

創(chuàng)建成功之后,pom.xml 文件如下:

 
 
 
 
  1.  
  2.     org.springframework.boot 
  3.     spring-boot-starter-data-redis 
  4.  
  5.  
  6.     org.springframework.boot 
  7.     spring-boot-starter-security 
  8.  
  9.  
  10.     org.springframework.boot 
  11.     spring-boot-starter-web 
  12.  
  13.  
  14.     org.springframework.session 
  15.     spring-session-data-redis 
  16.  

2.2 配置

 
 
 
 
  1. spring.redis.password=123 
  2. spring.redis.port=6379 
  3. spring.redis.host=127.0.0.1 
  4.  
  5. spring.security.user.name=javaboy 
  6. spring.security.user.password=123 
  7.  
  8. server.port=8080 

配置一下 Redis 的基本信息;Spring Security 為了簡(jiǎn)化,我就將用戶名密碼直接配置在 application.properties 中了,最后再配置一下項(xiàng)目端口號(hào)。

2.3 使用

配置完成后 ,就可以使用 Spring Session 了,其實(shí)就是使用普通的 HttpSession ,其他的 Session 同步到 Redis 等操作,框架已經(jīng)自動(dòng)幫你完成了:

 
 
 
 
  1. @RestController 
  2. public class HelloController { 
  3.     @Value("${server.port}") 
  4.     Integer port; 
  5.     @GetMapping("/set") 
  6.     public String set(HttpSession session) { 
  7.         session.setAttribute("user", "javaboy"); 
  8.         return String.valueOf(port); 
  9.     } 
  10.     @GetMapping("/get") 
  11.     public String get(HttpSession session) { 
  12.         return session.getAttribute("user") + ":" + port; 
  13.     } 

考慮到一會(huì) Spring Boot 將以集群的方式啟動(dòng) ,為了獲取每一個(gè)請(qǐng)求到底是哪一個(gè) Spring Boot 提供的服務(wù),需要在每次請(qǐng)求時(shí)返回當(dāng)前服務(wù)的端口號(hào),因此這里我注入了 server.port 。

接下來 ,項(xiàng)目打包:

 

打包之后,啟動(dòng)項(xiàng)目的兩個(gè)實(shí)例:

 
 
 
 
  1. java -jar session-4-0.0.1-SNAPSHOT.jar --server.port=8080 
  2. java -jar session-4-0.0.1-SNAPSHOT.jar --server.port=8081 

然后先訪問 localhost:8080/set 向 8080 這個(gè)服務(wù)的 Session 中保存一個(gè)變量,第一次訪問時(shí)會(huì)自動(dòng)跳轉(zhuǎn)到登錄頁(yè)面,輸入用戶名密碼進(jìn)行登錄即可。訪問成功后,數(shù)據(jù)就已經(jīng)自動(dòng)同步到 Redis 中 了 :

 

然后,再調(diào)用 localhost:8081/get 接口,就可以獲取到 8080 服務(wù)的 session 中的數(shù)據(jù):

 

此時(shí)關(guān)于 session 共享的配置就已經(jīng)全部完成了,session 共享的效果我們已經(jīng)看到了。

2.4 Security 配置

Session 共享已經(jīng)實(shí)現(xiàn)了,但是我們發(fā)現(xiàn)新的問題,在Spring Boot + Vue 前后端分離項(xiàng)目,如何踢掉已登錄用戶?一文中我們配置的 session 并發(fā)管理失效了。

也就是說,如果我添加了如下配置:

 
 
 
 
  1. protected void configure(HttpSecurity http) throws Exception { 
  2.     http.authorizeRequests().anyRequest() 
  3.             ... 
  4.             .sessionManagement() 
  5.             .maximumSessions(1) 
  6.             .maxSessionsPreventsLogin(true); 

現(xiàn)在這個(gè)配置不起作用,用戶依然可以在多個(gè)瀏覽器上同時(shí)登錄。

這是怎么回事呢?

在該文中,我們提到,會(huì)話注冊(cè)表的維護(hù)默認(rèn)是由 SessionRegistryImpl 來維護(hù)的,而 SessionRegistryImpl 的維護(hù)就是基于內(nèi)存的維護(hù)?,F(xiàn)在我們雖然啟用了 Spring Session+Redis 做 Session 共享,但是 SessionRegistryImpl 依然是基于內(nèi)存來維護(hù)的,所以我們要修改 SessionRegistryImpl 的實(shí)現(xiàn)邏輯。

修改方式也很簡(jiǎn)單,實(shí)際上 Spring Session 為我們提供了對(duì)應(yīng)的實(shí)現(xiàn)類 SpringSessionBackedSessionRegistry,具體配置如下:

 
 
 
 
  1. @Configuration 
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter { 
  3.     @Autowired 
  4.     FindByIndexNameSessionRepository sessionRepository; 
  5.     @Override 
  6.     protected void configure(HttpSecurity http) throws Exception { 
  7.         http.authorizeRequests().anyRequest() 
  8.                 ... 
  9.                 .sessionManagement() 
  10.                 .maximumSessions(1) 
  11.                 .maxSessionsPreventsLogin(true) 
  12.                 .sessionRegistry(sessionRegistry()); 
  13.     } 
  14.     @Bean 
  15.     SpringSessionBackedSessionRegistry sessionRegistry() { 
  16.         return new SpringSessionBackedSessionRegistry(sessionRepository); 
  17.     } 

我們?cè)谶@里只需要提供一個(gè) SpringSessionBackedSessionRegistry 的實(shí)例,并且將其配置到 sessionManagement 中去即可。以后,session 并發(fā)數(shù)據(jù)的維護(hù)將由 SpringSessionBackedSessionRegistry 來完成,而不是 SessionRegistryImpl,如此,我們關(guān)于 session 并發(fā)的配置就生效了,在集群環(huán)境下,用戶也只可以在一臺(tái)設(shè)備上登錄。

為了讓我們的案例看起更完美一些,接下來我們來引入 Nginx ,實(shí)現(xiàn)服務(wù)實(shí)例自動(dòng)切換。

3.引入 Nginx

很簡(jiǎn)單,進(jìn)入 Nginx 的安裝目錄的 conf 目錄下(默認(rèn)是在/usr/local/nginx/conf),編輯 nginx.conf 文件:

 

在這段配置中:

  1. upstream 表示配置上游服務(wù)器
  2. javaboy.org 表示服務(wù)器集群的名字,這個(gè)可以隨意取名字
  3. upstream 里邊配置的是一個(gè)個(gè)的單獨(dú)服務(wù)
  4. weight 表示服務(wù)的權(quán)重,意味者將有多少比例的請(qǐng)求從 Nginx 上轉(zhuǎn)發(fā)到該服務(wù)上
  5. location 中的 proxy_pass 表示請(qǐng)求轉(zhuǎn)發(fā)的地址,/ 表示攔截到所有的請(qǐng)求,轉(zhuǎn)發(fā)轉(zhuǎn)發(fā)到剛剛配置好的服務(wù)集群中
  6. proxy_redirect 表示設(shè)置當(dāng)發(fā)生重定向請(qǐng)求時(shí),nginx 自動(dòng)修正響應(yīng)頭數(shù)據(jù)(默認(rèn)是 Tomcat 返回重定向,此時(shí)重定向的地址是 Tomcat 的地址,我們需要將之修改使之成為 Nginx 的地址)。

配置完成后,將本地的 Spring Boot 打包好的 jar 上傳到 Linux ,然后在 Linux 上分別啟動(dòng)兩個(gè) Spring Boot 實(shí)例:

 
 
 
 
  1. nohup java -jar session-4-0.0.1-SNAPSHOT.jar --server.port=8080 & 
  2. nohup java -jar session-4-0.0.1-SNAPSHOT.jar --server.port=8081 & 

其中

  • nohup 表示當(dāng)終端關(guān)閉時(shí),Spring Boot 不要停止運(yùn)行
  • & 表示讓 Spring Boot 在后臺(tái)啟動(dòng)

配置完成后,重啟 Nginx:

 
 
 
 
  1. /usr/local/nginx/sbin/nginx -s reload 

Nginx 啟動(dòng)成功后,我們首先手動(dòng)清除 Redis 上的數(shù)據(jù),然后訪問192.168.66.128/set 表示向 session 中保存數(shù)據(jù),這個(gè)請(qǐng)求首先會(huì)到達(dá) Nginx 上,再由 Nginx 轉(zhuǎn)發(fā)給某一個(gè) Spring Boot 實(shí)例:

 

如上,表示端口為 8081 的 Spring Boot 處理了這個(gè) /set 請(qǐng)求,再訪問 /get 請(qǐng)求:

 

可以看到,/get 請(qǐng)求是被端口為 8080 的服務(wù)所處理的。

4.總結(jié)

本文主要向大家介紹了 Spring Session 的使用,另外也涉及到一些 Nginx 的使用 ,雖然本文較長(zhǎng),但是實(shí)際上 Spring Session 的配置沒啥,涉及到的配置也都很簡(jiǎn)單。

如果大家沒有在 SSM 架構(gòu)中用過 Spring Session ,可能不太好理解我們?cè)?Spring Boot 中使用 Spring Session 有多么方便,因?yàn)樵?SSM 架構(gòu)中,Spring Session 的使用要配置三個(gè)地方 ,一個(gè)是 web.xml 配置代理過濾器,然后在 Spring 容器中配置 Redis,最后再配置 Spring Session,步驟還是有些繁瑣的,而 Spring Boot 中直接幫我們省去了這些繁瑣的步驟!

好了 ,本文就說到這里,本文相關(guān)案例我已經(jīng)上傳到 GitHub ,大家可以自行下載:https://github.com/lenve/spring-security-samples


網(wǎng)頁(yè)題目:集群化部署,SpringSecurity要如何處理Session共享?
本文網(wǎng)址:http://m.5511xx.com/article/cdioegj.html