1. 程式人生 > >SpringBootSecurity學習(19)前後端分離版之OAuth2.0 token的儲存和管理

SpringBootSecurity學習(19)前後端分離版之OAuth2.0 token的儲存和管理

記憶體中儲存token

我們來繼續授權服務程式碼的下一個優化。現在授權服務中,token的儲存是儲存在記憶體中的,我們使用的是 InMemoryTokenStore :

file

圖中的tokenStore方法支援很多種令牌的儲存方式,來看一下:

  • InMemoryTokenStore:這個版本的實現是被預設採用的,它可以完美的工作在單伺服器上(即訪問併發量壓力不大的情況下,並且它在失敗的時候不會進行備份),大多數的專案都可以使用這個版本的實現來進行嘗試,你可以在開發的時候使用它來進行管理,因為不會被儲存到磁碟中,所以更易於除錯。

  • JwtTokenStore:這個版本的全稱是 JSON Web Token(JWT),它可以把令牌相關的資料進行編碼(因此對於後端服務來說,它不需要進行儲存,這將是一個重大優勢),但是它有一個缺點,那就是撤銷一個已經授權令牌將會非常困難,所以它通常用來處理一個生命週期較短的令牌以及撤銷重新整理令牌(refresh_token)。另外一個缺點就是這個令牌佔用的空間會比較大,如果你加入了比較多使用者憑證資訊。JwtTokenStore 不會儲存任何資料,但是它在轉換令牌值以及授權資訊方面與 DefaultTokenServices 所扮演的角色是一樣的。

  • JdbcTokenStore:這是一個基於JDBC的實現,令牌會被儲存進關係型資料庫。使用這個實現時,你可以在不同的伺服器之間共享令牌資訊,使用的時候請注意把"spring-jdbc"這個依賴加入到你的classpath當中。

  • RedisTokenStore : 這是一個基於Redis的實現,令牌會被保Redis快取中。使用這個實現時,你可以在不同的伺服器之間共享令牌資訊,使用的時候請注意把redis依賴加入到你的classpath當中。關於redis和資料庫儲存資料有什麼不同和需要注意的地方,這裡不再描述。

預設的 InMemoryTokenStore 方式儲存也是可以進行查詢和刪除的,我們來看一下,首先將 InMemoryTokenStore 配置為一個bean:

file

然後配置時呼叫這個bean:

file

我們來看一下 InMemoryTokenStore 類中對token有哪些操作:

file

從方法的名字可以看出,對token的增刪改查操作基本都是齊全的,我們來寫兩個方法查詢和刪除token:

file

類中注入的InMemoryTokenStore正是前面定義的bean,只有這樣才能操作記憶體中的token,下面來看一下測試,先根據前面的流程,申請到令牌,然後查詢令牌:

file

然後測試刪除令牌:

file

然後再根據令牌查詢受保護的資源,可以發現無法訪問了。

使用記憶體的方式雖然基本的功能都在,但是缺點上面也提到了,就是隻能工作在單伺服器上面,無法預設實現token共享,另外測試環境使用記憶體儲存也是比較好的選擇。

Redis儲存token

令牌除了可以儲存在記憶體中,還可以儲存在公共的地方,比如redis中,這樣單伺服器資料不同步的問題可以解決。儲存在redis中首先要引入依賴:

file

然後配置資料來源:

file

然後修改授權配置類,配置redis儲存的bean:

file

這樣redis儲存token的配置基本就完成了,然後仿照前面的記憶體儲存操作,寫兩個介面用來查詢和刪除redis中的token:

file

啟動專案,按照之前的流程獲取令牌,訪問保護資源,然後檢視redis,可以看到裡面儲存了我們獲取的令牌:

file

來看查詢token介面的效果:

file

來看刪除token介面的效果:

file

刪除後,redis中的token也刪除了:

file

只剩下三個重新整理的key。

JDBC儲存token

使用jdbc儲存token的方式也可以做到token共享,操作類是 JdbcTokenStore ,我們來看一下這個類:

file

類中定義了好多預設操作的sql語句,總共涉及到兩張表:oauth_access_token和oauth_refresh_token(如果客戶端的grant_type不支援refresh_token,則不會使用該表),來看一下 oauth_access_token 表的結構:

  • token_id:該欄位的值是將access_token的值通過MD5加密後儲存的

  • token:儲存將OAuth2AccessToken.java物件序列化後的二進位制資料, 是真實的AccessToken的資料值

  • authentication_id:該欄位具有唯一性, 其值是根據當前的username(如果有),client_id與scope通過MD5加密生成的. 具體實現請參考DefaultAuthenticationKeyGenerator.java類

  • user_name:登入時的使用者名稱, 若客戶端沒有使用者名稱(如grant_type="client_credentials"),則該值等於client_id

  • client_id:你懂得

  • authentication:儲存將OAuth2Authentication.java物件序列化後的二進位制資料

  • refresh_token :該欄位的值是將refresh_token的值通過MD5加密後儲存的

來看一下 oauth_refresh_token 表的欄位結構:

  • token_id:該欄位的值是將refresh_token的值通過MD5加密後儲存的.

  • token:儲存將OAuth2RefreshToken.java物件序列化後的二進位制資料.

  • authentication:儲存將OAuth2Authentication.java物件序列化後的二進位制資料

在資料庫中建立這兩張表:

file

file

然後在pom中引入jdbc依賴,在配置檔案中配置資料來源,此處不再演示。下一步修改授權配置類:

file

最後仿照前面,寫兩個查詢和刪除token的介面:

file

使用資料庫儲存token,比前面兩種方式多了很多方法和操作,來看 JdbcTokenStore 類:

file

除了增刪改查的操作多了幾個方法,包括sql語句的預設寫法也有覆蓋的set方法。下面來測試,首先按照前面的流程獲取token令牌,然後查詢資料庫:

file

file

可以看到資料庫中多了兩條token資料,看一下查詢token介面:

file

刪除介面:

file

看一下刪除介面呼叫的方法原始碼:

file

只是刪除了令牌,更新token的記錄還會保留。

程式碼地址: https://gitee.com/blueses/spring-boot-security 23 24

> 本文由部落格一文多發平臺 Op