實戰開發,使用 Spring Session 與 Spring security 完成網站登入改造!!
阿新 • • 發佈:2020-08-19
上次小黑在文章中介紹了[四種分散式一致性 Session 的實現方式](https://mp.weixin.qq.com/s/8HgFYgrJDC3bi5MY0icJfg),在這四種中最常用的就是後端集中儲存方案,這樣即使 web 應用重啟或者擴容,Session 都沒有丟失的風險。
![](https://img2020.cnblogs.com/other/1419561/202008/1419561-20200819073732307-816857285.jpg)
今天我們就使用這種方式對 Session 儲存方式進行改造,將其統一儲存到 Redis 中。
## 實現方案
我們先來想一下,如果我們不依靠任何框架,自己如何實現後端 **Session** 集中儲存。
這裡我們假設我們的網站除了某些頁面,比如首頁可以直接訪問以外,其他任何頁面都需要登入之後才能訪問。
如果需要實現這個需求,這就需要我們對每個請求都進行鑑權,鑑權目的是為了判斷使用者是否登入,判斷使用者角色。
如果使用者沒有登入,我們需要將請求強制跳轉到登入頁面進行登入。
使用者登入之後,我們需要將登入獲取到的使用者資訊儲存到 **Session** 中,這樣後面請求鑑權只需要判斷 **Session** 中是否存在即可。
知道整個流程之後,其實實現原理就不是很難了。
我們可以使用類似 **AOP** 的原理,在每個請求進來之後,都先判斷 Session 中是否存在使用者資訊,如果不存在就跳轉到登入頁。
整個流程如下所示:
![](https://img2020.cnblogs.com/other/1419561/202008/1419561-20200819073732698-806807378.jpg)
我們可以利用 **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 資訊,所以我們需要下述依賴即可。
```xml
org.springframework.session
spring-session-data-redis
```
如果不是 Spring Boot 專案,那主要需要引入如下依賴:
```xml
org.springframework.data
spring-data-redis
2.3.0.RELEASE
org.springframework.session
spring-session-core
2.3.0.RELEASE
```
引入依賴之後,我們首先需要在 `application.properties`增加 Session 相關的配置:
```properties
## Session 儲存方式
spring.session.store-type=redis
## Session 過期時間,預設單位為 s
server.servlet.session.timeout=600
## Session 儲存到 Redis 鍵的字首
spring.session.redis.namespace=test:spring:session
## Redis 相關配置
spring.redis.host=127.0.0.1
spring.redis.password=****
spring.redis.port=6379
```
配置完成之後,Spring Session 就會開始管理 Session 資訊,下面我們來測試一下:
```java
@ResponseBody
@GetMapping("/hello")
public String hello() {
return "Hello World";
}
```
當我們訪問上面地址之後,訪問 Redis ,可以看到儲存的 Session 資訊。
> 推薦大家一個 Redis 客戶端「Another Redis DeskTop Manager」,這個客戶端 UI 頁面非常漂亮,操作也很方便,下載地址:
>
> https://github.com/qishibo/anotherredisdesktopmanager/releases
![](https://img2020.cnblogs.com/other/1419561/202008/1419561-20200819073733056-1836698601.jpg)
預設情況下,Session 預設使用HttpSession 序列化方式,這種值看起來不夠直觀。我們可以將其修改成 json 序列化方式,儲存到 redis 中。
```java
@Configuration
public class HttpSessionConfig implements BeanClassLoaderAware {
private ClassLoader loader;
@Bean
public RedisSerializer