SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權


在前面的文章中,我們已經使用 token 實現前後端分離的系統登錄及訪問鑑權。

登錄成功後,服務端會生成一個 token 並存儲起來,這樣客戶端攜 token 再次訪問時,服務端就可以根據 token 獲取當前用戶的登錄狀態及用戶信息。在之前的示例中,我們將 token 存儲在數據庫中,客戶端每次訪問都需要從數據庫中讀取 token 相關聯的用戶信息。數據庫通常是系統的性能瓶頸,每次請求都需要先訪問數據庫,對數據庫來說壓力山大。

當然,我們使用 Redis 之類的高性能中間件來存儲 token,這樣相對來說,壓力來會減少,但是壓力依然在。那麼有沒有一種技術,在服務端獲取到 token 之後,可以直接根據 token 解析出用戶信息,這樣就可以避免從存儲中間件獲取信息給系統造成的壓力。

JWT(Java Web Token)就是這樣的一種技術。

相關知識

什麼是 JWT

請參考阮一峰博客 http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html,裡面有比較詳盡的介紹。

目標

整合 SpringSecurity 實現使用 JWT 進行登錄及訪問鑑權。

準備工作

創建用戶表 user、角色表 role、用戶角色關係表 user_role,因為 JWT 本身就是用戶信息,所以不用再另行存儲,可以直接解析

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

操作步驟

添加依賴

引入 Spring Boot Starter 父工程

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

添加 springSecurity 及 mybatisPlus 的依賴,添加後的整體依賴如下

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

配置

配置一下數據源

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

編碼

實體類

角色實體類 Role,實現權限接口 GrantedAuthority

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

用戶實體類 user,實現權限接口 UserDetails,主要方法是 getAuthorities,用於獲取用戶的角色列表

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

用戶角色關係實體

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

Repository 層

分別為三個實體類添加 Mapper

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

實現 UserDetailsService 接口

UserDetailsService 是 SpringSecurity 提供的登陸時用於根據用戶名獲取用戶信息的接口

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

自定義登錄參數格式

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

自定義登錄過濾器

繼承 SpringSecurity 提供的 AbstractAuthenticationProcessingFilter 類,實現 attemptAuthentication 方法,用於登錄校驗。

本例中,模擬前端使用 json 格式傳遞參數,所以通過 objectMapper.readValue 的方式從流中獲取入參,之後借用了用戶名密碼登錄的校驗,

如果鑑權成功,使用 JWT 工具類生成 token 並將 token 返回給前端。

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

自定義登陸成功後處理

實現 SpringSecurity 提供的 AuthenticationSuccessHandler 接口,使用 JSON 格式返回

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

自定義登陸失敗後處理

實現 SpringSecurity 提供的 AuthenticationFailureHandler 接口,使用 JSON 格式返回

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

自定義權限校驗失敗後處理

登陸成功之後,訪問接口之前 SpringSecurity 會進行鑑權,如果沒有訪問權限,需要對返回進行處理。實現 SpringSecurity 提供的 AccessDeniedHandler 接口,使用 JSON 格式返回

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

自定義未登錄後處理

實現 SpringSecurity 提供的 AuthenticationEntryPoint 接口,使用 JSON 格式返回

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

自定義 Token 驗證過濾器

客戶端登錄成功時,後臺會把生成的 token 返回給前端,之後客戶端每次請求後臺接口將會把這個 token 附在 header 頭中傳遞給後臺,後臺會使用 JWT 工具類進行驗證這個 token 是否有效,並把 JWT 中包含的信息解析成用戶對象,加載至 SpringSecurity 中。

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

JWT 工具類

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

註冊

在 configure 方法中將自定義的 jsonAuthenticationFilter 及 tokenAuthenticationFilter 註冊進 SpringSecurity 的過濾器鏈中,並禁用 session。

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

啟動類

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

驗證結果

初始化數據

SpringBoot2.0實戰(28)整合SpringSecurity之前後端分離JWT鑑權

源碼地址

本章源碼 : https://gitee.com/gongm_24/spring-boot-tutorial.git

結束語

與普通的 token 不同的是,JWT 作為 token 本身就已經包含了信息,而普通的 token 就只是一個字符串,需要用戶信息就必須再去數據庫或者其它中間件中進行加載,JWT 則可以省去這一步,這可以大幅度降低系統的 IO。

但是 JWT 也有自己的問題,那就是一旦生成,服務端將無法控制它,只要在有效期內就可以一直使用,所以 JWT 更適用於短期授權。


分享到:


相關文章: