通過筆者前兩篇文章的說明,相信大家已經知道JWT是什麼,怎麼用,該如何結合Spring Security使用。那麼本節就用代碼來具體的實現一下JWT登錄認證及鑑權的流程。為了大部分的移動端用戶觀看,本文所有代碼均用圖片的形式發布,圖片點擊可放大。
一、環境準備工作
建立Spring Boot項目併集成了Spring Security,項目可以正常啟動
通過controller寫一個HTTP的GET方法服務接口,比如:「/hello」
實現最基本的動態數據驗證及權限分配,即實現UserDetailsService接口和UserDetails接口。這兩個接口都是向Spring Security提供用戶、角色、權限等校驗信息的接口
如果你學習過Spring Security的formLogin登錄模式,請將HttpSecurity配置中的formLogin()配置段全部去掉。因為JWT完全使用JSON接口,沒有from表單提交。
HttpSecurity配置中一定要加上csrf().disable(),即暫時關掉跨站攻擊CSRF的防禦。這樣是不安全的,我們後續章節再做處理。
以上的內容,我們在之前的文章中都已經講過。如果仍然不熟悉,可以翻看本號之前的文章。
二、開發JWT工具類
通過maven坐標引入JWT工具包jjwt
圖片:JWT工具包maven坐標
在application.yml中加入如下自定義一些關於JWT的配置
jwt: header: JWTHeaderName secret: aabbccdd expiration: 3600000
其中header是攜帶JWT令牌的HTTP的Header的名稱。雖然我這裡叫做JWTHeaderName,但是在實際生產中可讀性越差越安全。
secret是用來為JWT基礎信息加密和解密的密鑰。雖然我在這裡在配置文件寫死了,但是在實際生產中通常不直接寫在配置文件裡面。而是通過應用的啟動參數傳遞,並且需要定期修改。
expiration是JWT令牌的有效時間。
寫一個Spring Boot配置自動加載的工具類。
圖片:開發JWT工具類
上面的代碼就是使用io.jsonwebtoken.jjwt提供的方法開發JWT令牌生成、刷新的工具類。
三、開發登錄接口(獲取Token的接口)
"/authentication"接口用於登錄驗證,並且生成JWT返回給客戶端
"/refreshtoken"接口用於刷新JWT,更新JWT令牌的有效期
圖片:開發登錄接口(獲取Token的接口)
核心的token業務邏輯寫在JwtAuthService 中
login方法中首先使用用戶名、密碼進行登錄驗證。如果驗證失敗拋出BadCredentialsException異常。如果驗證成功,程序繼續向下走,生成JWT響應給前端
refreshToken方法只有在JWT token沒有過期的情況下才能刷新,過期了就不能刷新了。需要重新登錄。
圖片:核心的token業務邏輯寫在JwtAuthService 中
因為使用到了AuthenticationManager ,所以在繼承WebSecurityConfigurerAdapter的SpringSecurity配置實現類中,將AuthenticationManager 聲明為一個Bean。並將"/authentication"和 "/refreshtoken" 開放訪問權限,如何開放訪問權限,我們之前的文章已經講過了。
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean();}
四、接口訪問鑑權過濾器
當用戶第一次登陸之後,我們將JWT令牌返回給了客戶端,客戶端應該將該令牌保存起來。在進行接口請求的時候,將令牌帶上,放到HTTP的header裡面,header的名字要和jwt.header的配置一致,這樣服務端才能解析到。下面我們定義一個攔截器:
攔截接口請求,從請求request獲取token,從token中解析得到用戶名
然後通過UserDetailsService獲得系統用戶(從資料庫、或其他其存儲介質)
根據用戶信息和JWT令牌,驗證系統用戶與用戶輸入的一致性,並判斷JWT是否過期。如果沒有過期,至此表明了該用戶的確是該系統的用戶。
但是,你是系統用戶不代表你可以訪問所有的接口。所以需要構造UsernamePasswordAuthenticationToken傳遞用戶、權限信息,並將這些信息通過authentication告知Spring Security。Spring Security會以此判斷你的接口訪問權限。
圖片:接口訪問鑑權過濾器
在spring Security的配置類(即WebSecurityConfigurerAdapter實現類的configure(HttpSecurity http)配置方法中,加入如下配置:
.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and().addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
因為我們使用了JWT,表明了我們的應用是一個前後端分離的應用,所以我們可以開啟STATELESS禁止使用session。當然這並不絕對,前後端分離的應用通過一些辦法也是可以使用session的,這不是本文的核心內容不做贅述。
將我們的自定義jwtAuthenticationTokenFilter,加載到UsernamePasswordAuthenticationFilter的前面。
五、PostMan測試一下:
測試登錄接口,即:獲取token的接口。輸入正確的用戶名、密碼即可獲取token。
圖片:測試登錄接口
下面我們訪問一個我們定義的簡單的接口「/hello」,但是不傳遞JWT令牌,結果是禁止訪問。當我們將上一步返回的token,傳遞到header中,就能正常響應hello的接口結果。
圖片:訪問接口「/hello」
通過zimug點靠m,更多精品合集知識等待你! 本號只做持續的知識輸出,希望您能關注、評論、轉發!您的支持是我不竭的創作動力!讓知識產生價值、讓程式設計師改變世界!