在前面的文章中,我們已經使用 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 本身就是用戶信息,所以不用再另行存儲,可以直接解析
操作步驟
添加依賴
引入 Spring Boot Starter 父工程
添加 springSecurity 及 mybatisPlus 的依賴,添加後的整體依賴如下
配置
配置一下數據源
編碼
實體類
角色實體類 Role,實現權限接口 GrantedAuthority
用戶實體類 user,實現權限接口 UserDetails,主要方法是 getAuthorities,用於獲取用戶的角色列表
用戶角色關係實體
Repository 層
分別為三個實體類添加 Mapper
實現 UserDetailsService 接口
UserDetailsService 是 SpringSecurity 提供的登陸時用於根據用戶名獲取用戶信息的接口
自定義登錄參數格式
自定義登錄過濾器
繼承 SpringSecurity 提供的 AbstractAuthenticationProcessingFilter 類,實現 attemptAuthentication 方法,用於登錄校驗。
本例中,模擬前端使用 json 格式傳遞參數,所以通過 objectMapper.readValue 的方式從流中獲取入參,之後借用了用戶名密碼登錄的校驗,
如果鑑權成功,使用 JWT 工具類生成 token 並將 token 返回給前端。
自定義登陸成功後處理
實現 SpringSecurity 提供的 AuthenticationSuccessHandler 接口,使用 JSON 格式返回
自定義登陸失敗後處理
實現 SpringSecurity 提供的 AuthenticationFailureHandler 接口,使用 JSON 格式返回
自定義權限校驗失敗後處理
登陸成功之後,訪問接口之前 SpringSecurity 會進行鑑權,如果沒有訪問權限,需要對返回進行處理。實現 SpringSecurity 提供的 AccessDeniedHandler 接口,使用 JSON 格式返回
自定義未登錄後處理
實現 SpringSecurity 提供的 AuthenticationEntryPoint 接口,使用 JSON 格式返回
自定義 Token 驗證過濾器
客戶端登錄成功時,後臺會把生成的 token 返回給前端,之後客戶端每次請求後臺接口將會把這個 token 附在 header 頭中傳遞給後臺,後臺會使用 JWT 工具類進行驗證這個 token 是否有效,並把 JWT 中包含的信息解析成用戶對象,加載至 SpringSecurity 中。
JWT 工具類
註冊
在 configure 方法中將自定義的 jsonAuthenticationFilter 及 tokenAuthenticationFilter 註冊進 SpringSecurity 的過濾器鏈中,並禁用 session。
啟動類
驗證結果
初始化數據
源碼地址
本章源碼 : https://gitee.com/gongm_24/spring-boot-tutorial.git
結束語
與普通的 token 不同的是,JWT 作為 token 本身就已經包含了信息,而普通的 token 就只是一個字符串,需要用戶信息就必須再去數據庫或者其它中間件中進行加載,JWT 則可以省去這一步,這可以大幅度降低系統的 IO。
但是 JWT 也有自己的問題,那就是一旦生成,服務端將無法控制它,只要在有效期內就可以一直使用,所以 JWT 更適用於短期授權。
閱讀更多 死牛胖子 的文章