引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

橘子發表於2020-08-11

今天我們就使用這種方式對 Session 儲存方式進行改造,將其統一儲存到 Redis 中。

實現方案

我們先來想一下,如果我們不依靠任何框架,自己如何實現後端 Session 集中儲存。

這裡我們假設我們的網站除了某些頁面,比如首頁可以直接訪問以外,其他任何頁面都需要登入之後才能訪問。

如果需要實現這個需求,這就需要我們對每個請求都進行鑑權,鑑權目的是為了判斷使用者是否登入,判斷使用者角色。

如果使用者沒有登入,我們需要將請求強制跳轉到登入頁面進行登入。

使用者登入之後,我們需要將登入獲取到的使用者資訊儲存到 Session 中,這樣後面請求鑑權只需要判斷 Session 中是否存在即可。

知道整個流程之後,其實實現原理就不是很難了。

我們可以使用類似 AOP 的原理,在每個請求進來之後,都先判斷 Session 中是否存在使用者資訊,如果不存在就跳轉到登入頁。

整個流程如下所示:

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

我們可以利用 Servelt Filter 實現上述流程,不過上述整套流程,Spring 已經幫我們實現了,那我們就不用重複造輪子了。

我們可以使用 Spring-Session 與 Spring-security 實現上述網站的流程。

Spring-Session 是 Spring 提供一套管理使用者 Session 的實現方案,使用 Spring-Session之後,預設 WEB 容器,比如 Tomcat,產生的 Session 將會被 Spring-Session 接管。

除此之外,Spring-Session 還提供幾種常見後端儲存實現方案,比如 Redis,資料庫等。

有了 Spring-Session 之後,它只是幫我們解決了 Session 後端集中儲存。但是上述流程中我們還需要登入授權,而這一塊我們可以使用 Spring-security 來實現。

Spring-security 可以維護統一的登入授權方式,同時它可以結合 Spring-Session 一起使用。使用者登入授權之後,獲取的使用者資訊可以自動儲存到 Spring-Session 中。

好了,不說廢話了,我們來看下實現程式碼。

下述使用 Spring Boot 實現, Spring-Boot 版本為:2.3.2.RELEASE

Spring Session

首先我們引入 Spring Session 依賴,這裡我們使用 Redis 集中儲存 Session 資訊,所以我們需要下述依賴即可。

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

如果不是 Spring Boot 專案,那主要需要引入如下依賴:

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

引入依賴之後,我們首先需要在 application.properties增加 Session 相關的配置:

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

配置完成之後,Spring Session 就會開始管理 Session 資訊,下面我們來測試一下:

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

當我們訪問上面地址之後,訪問 Redis ,可以看到儲存的 Session 資訊。

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

預設情況下,Session 預設使用HttpSession 序列化方式,這種值看起來不夠直觀。我們可以將其修改成 json 序列化方式,儲存到 redis 中。

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

修改之後 Redis 鍵值如下所示:

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

ps:這裡 Redis 鍵值含義,下次分析原始碼的時候,再做分析。

Spring Session 還存在一個 @EnableRedisHttpSession,我們可以在這個註解上配置 Spring Session 相關配置。

@EnableRedisHttpSession(redisNamespace = "test:session")

需要注意的是,如果使用這個註解,將會導致 application.properties Session 相關配置失效,也就是說 Spring Session 將會直接使用註解上的配置。

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

這裡比較推薦大家使用配置檔案的方式。

好了,Spring Session 到這裡我們就接入完成了。

Spring security

上面我們整合了 Spring Session,完成 Session 統一 Redis 儲存。接下來主要需要實現請求的登陸鑑權。

這一步我們使用 Spring security 實現統一的登陸鑑權服務,同樣的框架的還有 Shiro,這裡我們就使用 Spring 全家桶。

首先我們需要依賴的相應的依賴:

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

引入上面的依賴之後,應用啟動之後將會生成一個隨機密碼,然後所有的請求將會跳轉到一個 Spring security 的頁面。

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

這裡我們需要實現自己業務的登陸頁,所以我們需要自定義登入校驗邏輯。

在 Spring security 我們只需要實現 UserDetailsService介面,重寫loadUserByUsername方法邏輯。

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

上面程式碼實現,這裡主要在記憶體固定使用者名稱與密碼,真實環境下,我們需要修改成從資料庫查詢使用者資訊。

接著我們需要把 UserServiceImpl 配置到 Spring security 中。

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

上面的配置中,密碼部分我們使用 BCrypt 演算法加密,這裡需要注意,加密與解密需要使用同一種方式。

接著我們需要實現一個自定義的登陸頁面,這裡就懶得自己寫了,直接使用 spring-session-data-redis 頁面。

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

這裡需要注意一點,這裡 form 表單的請求地址使用 /auth/login,我們需要在下面配置中修改,預設情況下登入請求的地址需要為 /login。

接著我們在上面的 SecurityConfig 類增加相應配置方法:

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

這個方法可能比較長,重點解釋一下:

  • authorizeRequests方法內需要指定那些頁面需要鑑權,這裡我們指定靜態資源無需登入鑑權,其他請求我們都需要登入鑑權
  • formLogin 方法內修改預設的登入頁面地址,以及登入的請求地址。
  • logout在這裡面可以配置登出的相關配置。
  • rememberMe開啟這個功能之後,當內部 Session 過期之後,使用者還可以根據使用者瀏覽器中的 Cookie 資訊實現免登入的功能。

最後我們需要配置一些頁面的跳轉地址:

引入兩個依賴之後,我一週內就完成了網站的登入改造|實戰開發

 

到此為止,我們已經整合 Spring-Session 與 Spring-security 完成完整的網站的登入鑑權功能。從這個例子可以看到,引入這個兩個框架之後,我們只需要按照 Spring 規範開發即可,其他複雜實現原理我們都不需要自己實現了,這樣真的很方便

相關文章