1. 程式人生 > >springBoot整合spring security+JWT實現單點登入與許可權管理前後端分離--築基中期

springBoot整合spring security+JWT實現單點登入與許可權管理前後端分離--築基中期

## 寫在前面 在前一篇文章當中,我們介紹了springBoot整合spring security單體應用版,在這篇文章當中,我將介紹springBoot整合spring secury+JWT實現單點登入與許可權管理。 本文涉及的許可權管理模型是**基於資源的動態許可權管理**。資料庫設計的表有 user 、role、user_role、permission、role_permission。 單點登入當中,關於訪問者資訊的儲存有多種解決方案。如將其以key-value的形式儲存於redis資料庫中,訪問者令牌中存放key。校驗使用者身份時,憑藉訪問者令牌中的key去redis中找value,沒找到則返回“令牌已過期”,讓訪問者去(重新)認證。本文中的demo,是將訪問者資訊加密後存於token中返回給訪問者,訪問者攜帶令牌去訪問服務時,服務提供者直接解密校驗token即可。兩種實現各有優缺點。大家也可以嘗試著將本文中的demo的訪問者資訊儲存改造成存在redis中的方式。文末提供完整的程式碼及sql指令碼下載地址。 在進入正式步驟之前,我們需要了解以下知識點。 ### 單點登入SSO 單點登入也稱分散式認證,指的是在有多個系統的專案中,使用者經過一次認證,即可訪問該專案下彼此相互信任的系統。 ### 單點登入流程 給大家畫了個流程圖 ![](https://img2020.cnblogs.com/blog/2129357/202009/2129357-20200904171000777-435357689.png) ### 關於JWT jwt,全稱JSON Web Token,是一款出色的分散式身份校驗方案。 #### jwt由三個部分組成 1. 頭部:主要設定一些規範資訊,簽名部分的編碼格式就在頭部中宣告。 2. 有效載荷:token中存放有效資訊的部分,比如使用者名稱,使用者角色,過期時間等,但不適合放諸如密碼等敏感資料,會造成洩露。 3. 簽名:將頭部與載荷分別採用base64編碼後,用“.”相連,再加入鹽,最後使用頭部宣告的編碼型別進行編碼,就得到了簽名。 #### jwt生成的Token安全性分析 想要使得token不被偽造,就要確保簽名不被篡改。然而,其簽名的頭部和有效載荷使用base64編碼,這與明文無異。因此,我們只能在鹽上做手腳了。我們對鹽進行非對稱加密後,在將token發放給使用者。 ### RSA非對稱加密 1. 基本原理:同時生成兩把金鑰:私鑰和公鑰,私鑰隱祕儲存,公鑰可以下發給信任客戶端 。 - 公鑰加密:只有私鑰才能解密 - 私鑰加密:私鑰或者公鑰都能解密 2. 優缺點: - 優點:安全、難以破解 - 缺點:耗時,但是為了安全,這是可以接受的 ### SpringSecurity+JWT+RSA分散式認證思路分析 通過之前的學習,我們知道了spring security主要是基於過濾器鏈來做認證的,因此,如何打造我們的單點登入,突破口就在於spring security中的認證過濾器。 #### 使用者認證 在分散式專案當中,現在大多數都是前後端分離架構設計的,因此,我們需要能夠接收POST請求的認證引數,而不是傳統的表單提交。因此,我們需要修改修 改UsernamePasswordAuthenticationFilter過濾器中attemptAuthentication方法,讓其能夠接收請求體。 關於spring security的認證流程分析,大家可以參考我上一篇文章《[Spring Security認證流程分析--練氣後期](https://juejin.im/post/6863693023314706446)》。 另外,預設情況下,successfulAuthentication 方法在通過認證後,直接將認證資訊放到伺服器的session當中就ok了。而我們分散式應用當中,前後端分離,禁用了session。因此,我們需要在認證通過後生成token(載荷內具有驗證使用者身份必要的資訊)返回給使用者。 #### 身份校驗 預設情況下,BasicAuthenticationFilter過濾器中doFilterInternal方法校驗使用者是否登入,就是看session中是否有使用者資訊。在分散式應用當中,我們要修改為,驗證使用者攜帶的token是否合法,並解析出使用者資訊,交給SpringSecurity,以便於後續的授權功能可以正常使用。 ## 實現步驟 (預設大家一已經建立好了資料庫) ### 第一步:建立一個springBoot的project 這個父工程主要做依賴的版本管理。 其pom.xml檔案如下 ```xml ``` ### 第二步:建立三個子模組 其中,**common**模組作為公共模組存在,提供基礎服務,包括token的生成、rsa加密金鑰的生成與使用、Json序列化與反序列化。 **authentication-service**模組提供單點登入服務(使用者認證及授權)。 **product-service**模組模擬一個子系統。它主要負責提供介面呼叫和校驗使用者身份。 #### 建立**common**模組模組 #####修改pom.xml,新增jwt、json等依賴 pom.xml ```xml ``` ##### 建立一個JSON工具類 ```java **json工具類 * @author 賴柄灃 [email protected] * @version 1.0 * @date 2020/9/2 22:28 */ public class JsonUtils { public static final ObjectMapper MAPPER = new ObjectMapper(); private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class); private JsonUtils() { } public static String toString(Object obj) { if (obj == null) { return null; } if (obj.getClass() == String.class) { return (String) obj; } try { return MAPPER.writeValueAsString(obj); } catch (JsonProcessingException e) { logger.error("json序列化出錯:" + obj, e); return null; } } public