導航:首頁 > 文件管理 > 網關鑒權jwt配置文件

網關鑒權jwt配置文件

發布時間:2023-12-04 20:39:08

① 鑒權必須了解的 5 個兄弟:cookie、session、token、jwt、單點登錄

本文你將看到:

**「前端存儲」**這就涉及到一發、一存、一帶,發好辦,登陸介面直接返回給前端,存儲就需要前端想辦法了。

前端的存儲方式有很多。

有,cookie。cookie 也是前端存儲的一種,但相比於 localStorage 等其他方式,藉助 HTTP 頭、瀏覽器能力,cookie 可以做到前端無感知。一般過程是這樣的:

「配置:Domain / Path」

cookie 是要限制::「空間范圍」::的,通過 Domain(域)/ Path(路徑)兩級。

「配置:Expires / Max-Age」

cookie 還可以限制::「時間范圍」::,通過 Expires、Max-Age 中的一種。

「配置:Secure / HttpOnly」

cookie 可以限制::「使用方式」::。

**「HTTP 頭對 cookie 的讀寫」**回過頭來,HTTP 是如何寫入和傳遞 cookie 及其配置的呢?HTTP 返回的一個 Set-Cookie 頭用於向瀏覽器寫入「一條(且只能是一條)」cookie,格式為 cookie 鍵值 + 配置鍵值。例如:

那我想一次多 set 幾個 cookie 怎麼辦?多給幾個 Set-Cookie 頭(一次 HTTP 請求中允許重復)

HTTP 請求的 Cookie 頭用於瀏覽器把符合當前「空間、時間、使用方式」配置的所有 cookie 一並發給服務端。因為由瀏覽器做了篩選判斷,就不需要歸還配置內容了,只要發送鍵值就可以。

**「前端對 cookie 的讀寫」**前端可以自己創建 cookie,如果服務端創建的 cookie 沒加HttpOnly,那恭喜你也可以修改他給的 cookie。調用document.cookie可以創建、修改 cookie,和 HTTP 一樣,一次document.cookie能且只能操作一個 cookie。

調用document.cookie也可以讀到 cookie,也和 HTTP 一樣,能讀到所有的非HttpOnly cookie。

現在回想下,你刷卡的時候發生了什麼?

這種操作,在前後端鑒權系統中,叫 session。典型的 session 登陸/驗證流程:

**「Session 的存儲方式」**顯然,服務端只是給 cookie 一個 sessionId,而 session 的具體內容(可能包含用戶信息、session 狀態等),要自己存一下。存儲的方式有幾種:

「Session 的過期和銷毀」**很簡單,只要把存儲的 session 數據銷毀就可以。****「Session 的分布式問題」**通常服務端是集群,而用戶請求過來會走一次負載均衡,不一定打到哪台機器上。那一旦用戶後續介面請求到的機器和他登錄請求的機器不一致,或者登錄請求的機器宕機了,session 不就失效了嗎?這個問題現在有幾種解決方式。

但通常還是採用第一種方式,因為第二種相當於閹割了負載均衡,且仍沒有解決「用戶請求的機器宕機」的問題。**「node.js 下的 session 處理」**前面的圖很清楚了,服務端要實現對 cookie 和 session 的存取,實現起來要做的事還是很多的。在npm中,已經有封裝好的中間件,比如 express-session - npm,用法就不貼了。這是它種的 cookie:

express-session - npm 主要實現了:

session 的維護給服務端造成很大困擾,我們必須找地方存放它,又要考慮分布式的問題,甚至要單獨為了它啟用一套 Redis 集群。有沒有更好的辦法?

回過頭來想想,一個登錄場景,也不必往 session 存太多東西,那為什麼不直接打包到 cookie 中呢?這樣服務端不用存了,每次只要核驗 cookie 帶的「證件」有效性就可以了,也可以攜帶一些輕量的信息。這種方式通常被叫做 token。

token 的流程是這樣的:

**「客戶端 token 的存儲方式」 在前面 cookie 說過,cookie 並不是客戶端存儲憑證的唯一方式。token 因為它的「無狀態性」,有效期、使用限制都包在 token 內容里,對 cookie 的管理能力依賴較小,客戶端存起來就顯得更自由。但 web 應用的主流方式仍是放在 cookie 里,畢竟少操心。 「token 的過期」**那我們如何控制 token 的有效期呢?很簡單,把「過期時間」和數據一起塞進去,驗證時判斷就好。

編碼的方式豐儉由人。**「base64」**比如 node 端的 cookie-session - npm 庫

默認配置下,當我給他一個 userid,他會存成這樣:

這里的 eyJ1c2VyaWQiOiJhIn0=,就是 {"userid":"abb」} 的 base64 而已。 「防篡改」

是的。所以看情況,如果 token 涉及到敏感許可權,就要想辦法避免 token 被篡改。解決方案就是給 token 加簽名,來識別 token 是否被篡改過。例如在 cookie-session - npm 庫中,增加兩項配置:

這樣會多種一個 .sig cookie,裡面的值就是 {"userid":"abb」} 和 iAmSecret通過加密演算法計算出來的,常見的比如HMACSHA256 類 (System.Security.Cryptography) | Microsoft Docs。

好了,現在 cdd 雖然能偽造出eyJ1c2VyaWQiOiJhIn0=,但偽造不出 sig 的內容,因為他不知道 secret。**「JWT」**但上面的做法額外增加了 cookie 數量,數據本身也沒有規范的格式,所以 JSON Web Token Introction - jwt.io 橫空出世了。

它是一種成熟的 token 字元串生成方案,包含了我們前面提到的數據、簽名。不如直接看一下一個 JWT token 長什麼樣:

這串東西是怎麼生成的呢?看圖:

類型、加密演算法的選項,以及 JWT 標准數據欄位,可以參考 RFC 7519 - JSON Web Token (JWT)node 上同樣有相關的庫實現:express-jwt - npm koa-jwt - npm

token,作為許可權守護者,最重要的就是「安全」。業務介面用來鑒權的 token,我們稱之為 access token。越是許可權敏感的業務,我們越希望 access token 有效期足夠短,以避免被盜用。但過短的有效期會造成 access token 經常過期,過期後怎麼辦呢?一種辦法是,讓用戶重新登錄獲取新 token,顯然不夠友好,要知道有的 access token 過期時間可能只有幾分鍾。另外一種辦法是,再來一個 token,一個專門生成 access token 的 token,我們稱為 refresh token。

有了 refresh token 後,幾種情況的請求流程變成這樣:

如果 refresh token 也過期了,就只能重新登錄了。

session 和 token 都是邊界很模糊的概念,就像前面說的,refresh token 也可能以 session 的形式組織維護。狹義上,我們通常認為 session 是「種在 cookie 上、數據存在服務端」的認證方案,token 是「客戶端存哪都行、數據存在 token 里」的認證方案。對 session 和 token 的對比本質上是「客戶端存 cookie / 存別地兒」、「服務端存數據 / 不存數據」的對比。**「客戶端存 cookie / 存別地兒」**存 cookie 固然方便不操心,但問題也很明顯:

存別的地方,可以解決沒有 cookie 的場景;通過參數等方式手動帶,可以避免 CSRF 攻擊。 「服務端存數據 / 不存數據」

前面我們已經知道了,在同域下的客戶端/服務端認證系統中,通過客戶端攜帶憑證,維持一段時間內的登錄狀態。但當我們業務線越來越多,就會有更多業務系統分散到不同域名下,就需要「一次登錄,全線通用」的能力,叫做「單點登錄」。

簡單的,如果業務系統都在同一主域名下,比如wenku..com tieba..com,就好辦了。可以直接把 cookie domain 設置為主域名 .com,網路也就是這么乾的。

比如滴滴這么潮的公司,同時擁有didichuxing.com xiaojukeji.com didiglobal.com等域名,種 cookie 是完全繞不開的。這要能實現「一次登錄,全線通用」,才是真正的單點登錄。這種場景下,我們需要獨立的認證服務,通常被稱為 SSO。 「一次「從 A 系統引發登錄,到 B 系統不用登錄」的完整流程」

**「完整版本:考慮瀏覽器的場景」**上面的過程看起來沒問題,實際上很多 APP 等端上這樣就夠了。但在瀏覽器下不見得好用。看這里:

對瀏覽器來說,SSO 域下返回的數據要怎麼存,才能在訪問 A 的時候帶上?瀏覽器對跨域有嚴格限制,cookie、localStorage 等方式都是有域限制的。這就需要也只能由 A 提供 A 域下存儲憑證的能力。一般我們是這么做的:

圖中我們通過顏色把瀏覽器當前所處的域名標記出來。注意圖中灰底文字說明部分的變化。

謝謝大家哦

② 單點登錄JWT與Spring Security OAuth

通過 JWT 配合 Spring Security OAuth2 使用的方式,可以避免 每次請求 遠程調度 認證授權服務。 資源伺服器 只需要從 授權伺服器 驗證一次,返回 JWT。返回的 JWT 包含了 用戶 的所有信息,包括 許可權信息

1. 什麼是JWT

JSON Web Token(JWT)是一種開放的標准(RFC 7519),JWT 定義了一種 緊湊 自包含 的標准,旨在將各個主體的信息包裝為 JSON 對象。 主體信息 是通過 數字簽名 進行 加密 驗證 的。經常使用 HMAC 演算法或 RSA( 公鑰 / 私鑰 非對稱性加密 )演算法對 JWT 進行簽名, 安全性很高

2. JWT的結構

JWT 的結構由三部分組成:Header(頭)、Payload(有效負荷)和 Signature(簽名)。因此 JWT 通常的格式是 xxxxx.yyyyy.zzzzz。

2.1. Header

Header 通常是由 兩部分 組成:令牌的 類型 (即 JWT)和使用的 演算法類型 ,如 HMAC、SHA256 和 RSA。例如:

將 Header 用 Base64 編碼作為 JWT 的 第一部分 ,不建議在 JWT 的 Header 中放置 敏感信息

2.2. Payload

下面是 Payload 部分的一個示例:

將 Payload 用 Base64 編碼作為 JWT 的 第二部分 ,不建議在 JWT 的 Payload 中放置 敏感信息

2.3. Signature

要創建簽名部分,需要利用 秘鑰 對 Base64 編碼後的 Header 和 Payload 進行 加密 ,加密演算法的公式如下:

簽名 可以用於驗證 消息 傳遞過程 中有沒有被更改。對於使用 私鑰簽名 的 token,它還可以驗證 JWT 的 發送方 是否為它所稱的 發送方

3. JWT的工作方式

客戶端 獲取 JWT 後,對於以後的 每次請求 ,都不需要再通過 授權服務 來判斷該請求的 用戶 以及該 用戶的許可權 。在微服務系統中,可以利用 JWT 實現 單點登錄 。認證流程圖如下:

4. 案例工程結構

工程原理示意圖如下:

5. 構建auth-service授權服務

UserServiceDetail.java

UserRepository.java

實體類 User 和上一篇文章的內容一樣,需要實現 UserDetails 介面,實體類 Role 需要實現 GrantedAuthority 介面。

User.java

Role.java

jks 文件的生成需要使用 Java keytool 工具,保證 Java 環境變數沒問題,輸入命令如下:

其中,-alias 選項為 別名 ,-keyalg 為 加密演算法 ,-keypass 和 -storepass 為 密碼選項 ,-keystore 為 jks 的 文件名稱 ,-validity 為配置 jks 文件 過期時間 (單位:天)。

生成的 jks 文件作為 私鑰 ,只允許 授權服務 所持有,用作 加密生成 JWT。把生成的 jks 文件放到 auth-service 模塊的 src/main/resource 目錄下即可。

對於 user-service 這樣的 資源服務 ,需要使用 jks 的 公鑰 對 JWT 進行 解密 。獲取 jks 文件的 公鑰 的命令如下:

這個命令要求安裝 openSSL 下載地址,然後手動把安裝的 openssl.exe 所在目錄配置到 環境變數

輸入密碼 fzp123 後,顯示的信息很多,只需要提取 PUBLIC KEY,即如下所示:

新建一個 public.cert 文件,將上面的 公鑰信息 復制到 public.cert 文件中並保存。並將文件放到 user-service 等 資源服務 的 src/main/resources 目錄下。至此 auth-service 搭建完畢。

maven 在項目編譯時,可能會將 jks 文件 編譯 ,導致 jks 文件 亂碼 ,最後不可用。需要在 pom.xml 文件中添加以下內容:

6. 構建user-service資源服務

注入 JwtTokenStore 類型的 Bean,同時初始化 JWT 轉換器 JwtAccessTokenConverter,設置用於解密 JWT 的 公鑰

配置 資源服務 的認證管理,除了 注冊 登錄 的介面之外,其他的介面都需要 認證

新建一個配置類 GlobalMethodSecurityConfig,通過 @EnableGlobalMethodSecurity 註解開啟 方法級別 安全驗證

拷貝 auth-service 模塊的 User、Role 和 UserRepository 三個類到本模塊。在 Service 層的 UserService 編寫一個 插入用戶 的方法,代碼如下:

配置用於用戶密碼 加密 的工具類 BPwdEncoderUtil:

實現一個 用戶注冊 的 API 介面 /user/register,代碼如下:

在 Service 層的 UserServiceDetail 中添加一個 login() 方法,代碼如下:

AuthServiceClient 作為 Feign Client,通過向 auth-service 服務介面 /oauth/token 遠程調用獲取 JWT。在請求 /oauth/token 的 API 介面中,需要在 請求頭 傳入 Authorization 信息, 認證類型 ( grant_type )、用戶名 ( username ) 和 密碼 ( password ),代碼如下:

其中,AuthServiceHystrix 為 AuthServiceClient 的 熔斷器 ,代碼如下:

JWT 包含了 access_token、token_type 和 refresh_token 等信息,代碼如下:

UserLoginDTO 包含了一個 User 和一個 JWT 成員屬性,用於返回數據的實體:

登錄異常類 UserLoginException

全局異常處理 切面類 ExceptionHandle

在 Web 層的 UserController 類中新增一個登錄的 API 介面 /user/login 如下:

依次啟動 eureka-service,auth-service 和 user-service 三個服務。

7. 使用Postman測試

因為沒有許可權,訪問被拒絕。在資料庫手動添加 ROLE_ADMIN 許可權,並與該用戶關聯。重新登錄並獲取 JWT,再次請求 /user/foo 介面。

在本案例中,用戶通過 登錄介面 來獲取 授權服務 加密後的 JWT。用戶成功獲取 JWT 後,在以後每次訪問 資源服務 的請求中,都需要攜帶上 JWT。 資源服務 通過 公鑰解密 JWT, 解密成功 後可以獲取 用戶信息 許可權信息 ,從而判斷該 JWT 所對應的 用戶 是誰,具有什麼 許可權

獲取一次 Token,多次使用, 資源服務 不再每次訪問 授權服務 該 Token 所對應的 用戶信息 和用戶的 許可權信息

一旦 用戶信息 或者 許可權信息 發生了改變,Token 中存儲的相關信息並 沒有改變 ,需要 重新登錄 獲取新的 Token。就算重新獲取了 Token,如果原來的 Token 沒有過期,仍然是可以使用的。一種改進方式是在登錄成功後,將獲取的 Token 緩存 網關上 。如果用戶的 許可權更改 ,將 網關 上緩存的 Token 刪除 。當請求經過 網關 ,判斷請求的 Token 在 緩存 中是否存在,如果緩存中不存在該 Token,則提示用戶 重新登錄

閱讀全文

與網關鑒權jwt配置文件相關的資料

熱點內容
630升級工程武器 瀏覽:936
用換機助手接收的軟體文件在哪找 瀏覽:282
閱達app一教一輔五年級有哪些 瀏覽:7
win10系統用f2調節音量 瀏覽:19
壓縮文件密碼器 瀏覽:840
線下活動數據分析有哪些 瀏覽:314
助聽器插片式編程線如何連接 瀏覽:293
怎麼刪除系統休眠文件 瀏覽:914
搜索文件內容中包含的文字並替換 瀏覽:542
微信相冊程序圖標 瀏覽:714
win8怎麼顯示文件格式 瀏覽:547
文件伺服器中毒 瀏覽:721
如何修改網站訪問次數 瀏覽:518
mdfldf是什麼文件 瀏覽:569
文件在桌面怎麼刪除干凈 瀏覽:439
馬蘭士67cd機版本 瀏覽:542
javaweb爬蟲程序 瀏覽:537
word中千位分隔符 瀏覽:392
迷你編程七天任務的地圖怎麼過 瀏覽:844
word2003格式不對 瀏覽:86

友情鏈接