基于SpringSecurity的Jwt認證和授權(quán)

背景介紹

網(wǎng)上搜索jwt有很多實現(xiàn),但是大部分都是基于jjwt依賴自己實現(xiàn)jwt的生成邏輯,在Spring Security中結(jié)合Oauth2可以以少量代碼即可實現(xiàn)Jwt功能,將邏輯轉(zhuǎn)移到上層的框架中,可以有效的避免自寫代碼的安全漏洞,本項目
基于Springboot3的Spring Security搭建一套微服務(wù)的認證授權(quán)框架,和大家分享,附上GitHub代碼。
Spring-security-jwt代碼地址

Goals

  • 實現(xiàn)jwt認證(Authentication)
  • 實現(xiàn)基于jwt的方法級授權(quán)(Authorization)
  • 實現(xiàn)在安全模式下的swagger文檔(附帶)

Assumption

  • 本項目使用spring-boot 3.0.4,jdk版本為17
  • 使用了pring-security-oauth2-authorization-server來實現(xiàn)Authorization server
  • Jwt本身的認證功能可以通過Oauth2的spring-boot-starter-oauth2-resource-server包實現(xiàn),所以本次實現(xiàn)去除了jjwt的依賴,借助spring-boot-starter-oauth2-resource-serverspring-boot-starter-security實現(xiàn)
  • 為了方便調(diào)試,添加了swagger-ui支持,文檔地址為/swagger-ui.html,基于springdoc而不是springfox,注解有點區(qū)別,只是簡單地進行了實現(xiàn)

Out of scope

  • Oauth2包含好幾種認證機制,本次實現(xiàn)只用于微服務(wù)的jwt Token
  • MethodSecurity有三種類型,在EnableMethodSecurity注解中聲明,分別是jsr250Enabled,prePostEnabled,securedEnabled,項目實現(xiàn)了prePostEnabled中的@PreAuthorize和簡單的@RolesAllowed。@RolesAllowed是通過Jsr250AuthorizationManager處理的,不進行展開
  • 只添加了幾個jwt Claim,claim的最佳實踐需要自行研究,如果要更改還涉及到j(luò)wt轉(zhuǎn)化。
  • web-service在解析jwt的時候未做更多的自定義,可在/preAuthorize/id端點看到,直接使用了authentication.name來映射jwt中的sub, 要走Principal的需要自己轉(zhuǎn)化

Approach

整體流程

本次實現(xiàn)包含三個部分,附上三個部分的流程圖

  • Jwt認證流程(圖片不清晰,請參考github etc目錄下plantuml文件)


    JwtAuthentication-jwt_Authentication_Diagram.png
  • 基于Jwt的prePostEnabled授權(quán)流程

JwtAuorization-Jwt_PreAuthorize_Authorization_Diagram.png
  • Spring Security對于url的授權(quán)流程
SpringsecurityAuthorization-Spring_Security_Authorization_Diagram.png

Components

示例代碼有三個項目組成,具體參考github的README.

  • Auth-Service
  • Web-service
  • Simple-jwt-service

Jwt認證流程解析

jwt的認證是基于Filter來做的,請求進來時FilterChain中的BearerTokenAuthenticationFilter被調(diào)用,

Screenshot 2023-04-10 at 00.09.09.png

由代碼可知,這里實現(xiàn)了認證過程和SecurityContext的創(chuàng)建,我們繼續(xù)authenticate,這里面持續(xù)地調(diào)用下層,到JwtAuthenticationProvider

Screenshot 2023-04-10 at 00.16.55.png

這個authenticate基本是實際認證的地方了,有兩個點,一個是jwtDecoder,一個是jwtAuthenticationConverter。

  • 我們先拋出一個問題:JWT到底是如何認證的?
    查看auth-service的代碼,我們可以發(fā)現(xiàn)jwt token是基于密鑰對生成的,密鑰對舉兩個常用場景:
    1. 加密。像https,客戶端使用公鑰加密對稱密鑰,服務(wù)端使用私鑰解密,在接下來的通信中使用對稱密鑰加密數(shù)據(jù)。
    2. 簽名。像jwt,jwt三部分的最后一部分Sigature即為Auth-service使用私鑰進行的簽名,web-service在啟動的時候會自動裝配OAuth2ResourceServerJwtConfiguration
      Screenshot 2023-04-10 at 00.26.29.png

里面有幾個conditional的bean注入,我們看這個,當issuerUri存在時,會向auth-service拉取jwks,依據(jù)公鑰生成jwtDecoder,用decoder去解析jwt(上面圖中有),這個過程也附帶了認證的過程,同時這里會注冊兩個validator,一個是issuerUri(jwt中的iss和applicaiton.yml配置的)是否一致,一個是驗證jwt有效時間,在JwtValidators.createDefaultWithIssuer()中有聲明.

附 jwks example 
http://127.0.0.1:8081/oauth2/jwks

{
   "keys":[
      {
         "kty":"RSA",
         "e":"AQAB",
         "kid":"e902868c-50ec-419c-a85a-1e181794577e",
         "n":"3FlqJr5TRskIQIgdE3Dd7D9lboWdcTUT8a-fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRvc5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4_1tfRgG6ii4Uhxh6iI8qNMJQX-fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2kJdJ_ZIV-WW4noDdzpKqHcwmB8FsrumlVY_DNVvUSDIipiq9PbP4H99TXN1o746oRaNa07rq1hoCgMSSy-85SagCoxlmyE-D-of9SsMY8Ol9t0rdzpobBuhyJ_o5dfvjKw"
      }
   ]
}
  • jwtAuthenticationConverter轉(zhuǎn)換
    在web-service的WebSecureConfig中,自定義了一個jwtAuthenticationConverter
    Screenshot 2023-04-10 at 00.36.12.png

這個轉(zhuǎn)換器在JwtAuthenticationProvider中調(diào)用,把jwt轉(zhuǎn)換成AbstractAuthenticationToken(最開始的圖),

Screenshot 2023-04-10 at 00.39.40.png

converter過程我們簡單分為兩部分,一部分是sub轉(zhuǎn)換,一部分是權(quán)限轉(zhuǎn)換。
默認權(quán)限轉(zhuǎn)換時會使用jwt中的scp域,并加上SCOPE_前綴
配置中jwtGrantedAuthoritiesConverter.setAuthorityPrefix("");即為去除SCOPE_前綴

Jwt PreAuth授權(quán)解析

prePostEnabled檢查是基于aop實現(xiàn)的,配置類為PrePostMethodSecurityConfiguration, 入口類為AuthorizationManagerBeforeMethodInterceptor,執(zhí)行attemptAuthorization方法

Screenshot 2023-04-10 at 00.48.24.png

最后Spring EL表達式驗證,可參考流程圖,不再展開。

SpringSecurity Authorization 解析

SpringSecurity Authorization 是指對允許訪問的URL的授權(quán)認證


Screenshot 2023-04-10 at 00.50.44.png

即我們在WebSecureConfig中配置的url端點授權(quán),基于filterchain,入口為AuthorizationFilter,具體參考流程圖,不再展開。

如有錯誤,請指正,也歡迎更好的實現(xiàn)。

參考文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容