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

  • 2019 年 10 月 11 日
  • 筆記

內存中存儲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

本文由博客一文多發平台 OpenWrite 發佈!