AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當(dāng)前位置:首頁 > 科技  > 軟件

快手二面:有了Cookie和Session 為什么還要JWT ?你說一下JWT的原理?

來源: 責(zé)編: 時(shí)間:2024-04-23 18:03:58 169觀看
導(dǎo)讀引言在業(yè)務(wù)系統(tǒng)開發(fā)中,用戶身份驗(yàn)證是保障系統(tǒng)服務(wù)安全性的基石。無論是社交網(wǎng)絡(luò)、電商平臺還是企業(yè)級應(yīng)用,都需要確保用戶的訪問權(quán)限與行為與其真實(shí)身份相符。為了達(dá)到這一目的,我們通常采用了一系列技術(shù)手段來管理用戶

引言

在業(yè)務(wù)系統(tǒng)開發(fā)中,用戶身份驗(yàn)證是保障系統(tǒng)服務(wù)安全性的基石。無論是社交網(wǎng)絡(luò)、電商平臺還是企業(yè)級應(yīng)用,都需要確保用戶的訪問權(quán)限與行為與其真實(shí)身份相符。為了達(dá)到這一目的,我們通常采用了一系列技術(shù)手段來管理用戶會話并驗(yàn)證其身份,其中最常見的是Cookie和Session機(jī)制。但是,在近年來隨著微服務(wù)以及API驅(qū)動架構(gòu)的發(fā)展,JSON Web Tokens(JWT)作為一種輕量級的身份驗(yàn)證方案得到了廣泛的關(guān)注和應(yīng)用。Ish28資訊網(wǎng)——每日最新資訊28at.com

那么,JWT究竟是什么?它的原理是如何運(yùn)作的?又為何在已有Cookie和Session的基礎(chǔ)上,仍需要引入JWT作為身份驗(yàn)證的一種新方法呢?Ish28資訊網(wǎng)——每日最新資訊28at.com

Cookie和Session

Cookie是什么?

Cookie是Web開發(fā)中一種關(guān)鍵的客戶端存儲技術(shù),它是由Web服務(wù)器在用戶訪問時(shí)生成并發(fā)送至用戶瀏覽器的微型數(shù)據(jù)包,以文本文件的形式儲存在用戶的設(shè)備上。瀏覽器根據(jù)HTTP協(xié)議的規(guī)定,在之后對同一服務(wù)器的所有請求中自動附帶這些Cookie信息。Ish28資訊網(wǎng)——每日最新資訊28at.com

服務(wù)器通過在HTTP響應(yīng)頭中設(shè)置Set-Cookie字段,來指示瀏覽器保存具有特定名稱、值和其他配置參數(shù)(例如有效期、安全選項(xiàng)、路徑限制、域名限制等)的Cookie。這樣,每一個(gè)Cookie實(shí)質(zhì)上就是一對鍵值對,幫助服務(wù)器識別和區(qū)分不同的用戶及其在網(wǎng)站上的交互歷史。Ish28資訊網(wǎng)——每日最新資訊28at.com

Cookie的一個(gè)核心應(yīng)用是在用戶身份驗(yàn)證和會話管理方面,它可存儲用戶的會話ID,使得用戶在不同頁面間切換或重新打開網(wǎng)站時(shí),服務(wù)器能夠基于這個(gè)ID重建用戶的會話狀態(tài),實(shí)現(xiàn)無縫登錄和個(gè)性化體驗(yàn)。此外,Cookie還廣泛應(yīng)用于記錄用戶喜好、統(tǒng)計(jì)分析用戶行為、廣告定向投放等方面,以提升用戶體驗(yàn)和服務(wù)質(zhì)量。但是,由于Cookie可能涉及用戶隱私,現(xiàn)代瀏覽器和相關(guān)法規(guī)越來越重視對Cookie使用的透明度和用戶控制權(quán)。Ish28資訊網(wǎng)——每日最新資訊28at.com

Seeion是什么?

Session作為一種服務(wù)器端機(jī)制,旨在管理和維護(hù)用戶在其交互期間的狀態(tài)信息,這些信息被安全地存儲在服務(wù)器內(nèi)存或者持久化存儲(如數(shù)據(jù)庫)中,與僅在客戶端存儲的Cookie形成了鮮明對比。每當(dāng)用戶開始與服務(wù)器建立聯(lián)系時(shí),服務(wù)器會初始化一個(gè)新的Session對象,并將其狀態(tài)數(shù)據(jù)保存在服務(wù)器內(nèi)部資源中。Ish28資訊網(wǎng)——每日最新資訊28at.com

一旦Session建立,服務(wù)器會產(chǎn)生一個(gè)獨(dú)一無二的Session標(biāo)識符——Session ID,該ID隨后會通過HTTP響應(yīng)中的Cookie(通常命名規(guī)則包括但不限于JSESSIONID)下發(fā)至客戶端瀏覽器進(jìn)行存儲。此后,用戶的每一次請求都將攜帶著這個(gè)Session ID,服務(wù)器通過解析請求中的Session ID,能夠在自身的Session存儲區(qū)域內(nèi)檢索到相對應(yīng)的Session對象,從而實(shí)時(shí)獲取并更新用戶會話的具體狀態(tài)。Ish28資訊網(wǎng)——每日最新資訊28at.com

Session機(jī)制廣泛應(yīng)用在諸如認(rèn)證授權(quán)場景中,用來持久化登錄用戶的憑證和權(quán)限等敏感信息,確保用戶在瀏覽網(wǎng)站的不同頁面時(shí)仍能維持登錄狀態(tài)和個(gè)性化體驗(yàn)。此外,Session還能用于暫存用戶會話過程中的臨時(shí)數(shù)據(jù),比如購物車的內(nèi)容、網(wǎng)頁表單填寫的中間狀態(tài)等,直至?xí)捵匀唤K止(如超時(shí))、用戶主動登出或清理Session時(shí),這些數(shù)據(jù)才會失效。Ish28資訊網(wǎng)——每日最新資訊28at.com

但是雖然Cookie和Session在會話管理中一直使用,但它們存在一些缺點(diǎn)如下:Ish28資訊網(wǎng)——每日最新資訊28at.com

  • Cookie數(shù)量和大小限制:瀏覽器對Cookie的數(shù)量和大小有限制,可能導(dǎo)致用戶數(shù)據(jù)存儲受限。
  • 服務(wù)器資源占用:Session需要在服務(wù)器端存儲大量用戶會話信息,隨著并發(fā)用戶數(shù)的增長,可能會造成服務(wù)器內(nèi)存資源緊張。
  • 跨域問題:Cookie默認(rèn)遵循同源策略,不便于跨域共享會話狀態(tài)。
  • 分布式系統(tǒng)中的Session同步:在分布式環(huán)境或集群部署的情況下,Session數(shù)據(jù)需要在各服務(wù)器之間同步,增加了系統(tǒng)的復(fù)雜性。

為解決上述會話管理中的缺點(diǎn),以及對無狀態(tài)服務(wù)、更好的擴(kuò)展性和安全性要求,JWT這樣的新型身份驗(yàn)證技術(shù)就這樣誕生了。JWT通過將用戶信息加密打包成Token,讓客戶端自行攜帶認(rèn)證信息,從而實(shí)現(xiàn)了服務(wù)器的無狀態(tài)化。Ish28資訊網(wǎng)——每日最新資訊28at.com

JWT是什么?

JSON Web Tokens (JWT) 是一種開放標(biāo)準(zhǔn)(RFC 7519),定義了一種緊湊、自包含的方式來安全地在各方之間傳輸信息。JWT主要由三個(gè)部分組成,即Header(頭部)、Payload(載荷)和Signature(簽名),這三部分之間通過.分隔。Ish28資訊網(wǎng)——每日最新資訊28at.com

JWT的組成JWT的組成Ish28資訊網(wǎng)——每日最新資訊28at.com

JWT的內(nèi)容采用Base64編碼,可以直接嵌入到HTTP請求頭或者URL查詢參數(shù)中,因其具有可讀性、自包含和防篡改的特點(diǎn)而廣泛應(yīng)用在身份驗(yàn)證和授權(quán)場景中。Ish28資訊網(wǎng)——每日最新資訊28at.com

Header

描述了所使用的JWT類型(通常為JWT)以及簽名算法(如HS256、RS256等)。Ish28資訊網(wǎng)——每日最新資訊28at.com

? typ: 表明這是一個(gè)JWT(固定為 "JWT")。Ish28資訊網(wǎng)——每日最新資訊28at.com

? alg: 指定用于簽署JWT的算法,如 "HS256"(HMAC SHA-256)或 "RS256"(RSA SHA-256)等。Ish28資訊網(wǎng)——每日最新資訊28at.com

{  "alg": "HS256",  "typ": "JWT"}

Payload

包含了實(shí)際要傳遞的數(shù)據(jù),可以是任意的JSON對象,包含一組稱為聲明(claims)的數(shù)據(jù)。一般為用戶身份信息(如用戶ID、角色、權(quán)限等)和其他自定義聲明,還包含一個(gè)exp(Expiration Time)字段來設(shè)置JWT的有效期以及其他元數(shù)據(jù)。聲明分為三種類型:Ish28資訊網(wǎng)——每日最新資訊28at.com

  1. Registered Claims(注冊聲明) 這些是預(yù)先定義好的標(biāo)準(zhǔn)聲明,雖然不是必須的,但在JWT規(guī)范中建議使用。它們提供了一套通用的信息,有助于JWT的標(biāo)準(zhǔn)化處理。常見的注冊聲明包括:

? iss(issuer):簽發(fā)JWT的實(shí)體。Ish28資訊網(wǎng)——每日最新資訊28at.com

? sub(subject):JWT所面向的用戶或主題。Ish28資訊網(wǎng)——每日最新資訊28at.com

? aud(audience):預(yù)期接收J(rèn)WT的受眾。Ish28資訊網(wǎng)——每日最新資訊28at.com

? exp(expiration time):JWT過期時(shí)間,在此時(shí)間之后JWT應(yīng)被視為無效。Ish28資訊網(wǎng)——每日最新資訊28at.com

? nbf(not before):JWT生效時(shí)間之前,不應(yīng)被接受處理的時(shí)間點(diǎn)。Ish28資訊網(wǎng)——每日最新資訊28at.com

? iat(issued at):JWT的創(chuàng)建時(shí)間。Ish28資訊網(wǎng)——每日最新資訊28at.com

? jti(JWT ID):JWT的唯一標(biāo)識符,可用于防止重放攻擊。Ish28資訊網(wǎng)——每日最新資訊28at.com

2. Public Claims(公共聲明) 公共聲明是預(yù)留用于行業(yè)共識的標(biāo)準(zhǔn)聲明,雖然目前并未正式注冊到IANA JSON Web Token Registry,但可以在IANA JSON Web Token Registry 查看已注冊的聲明集。如果沒有官方注冊,但多個(gè)項(xiàng)目間需要共享相同的聲明,可以選擇將聲明名稱以特定前綴(如 urn:<namespace>:<name>)進(jìn)行命名,避免沖突。Ish28資訊網(wǎng)——每日最新資訊28at.com

3. Private Claims(私有聲明) 私有聲明是用于應(yīng)用內(nèi)部約定的自定義聲明,我們可以根據(jù)自己業(yè)務(wù)需求自由定義。例如,可以包含用戶ID (userId)、用戶角色 (role)、郵箱地址 (email) 等任何想要在JWT中傳遞的信息。Ish28資訊網(wǎng)——每日最新資訊28at.com

示例:Ish28資訊網(wǎng)——每日最新資訊28at.com

{  "sub": "1234567890",  "name": "John Doe",  "admin": true,  "iat": 1516239022,  "jti": "1pmysetgujcoden",  "exp": 1516242622,  "scope": [    "read",    "write"  ]}

Payload部分默認(rèn)是不加密的,一定不要將隱私信息存放在 Payload 當(dāng)中!!!Ish28資訊網(wǎng)——每日最新資訊28at.com

Signature

Signature部分用于確保JWT在傳輸過程中沒有被篡改,它是通過對前兩部分(Header和Payload編碼后的字符串)使用Header中指定的加密算法以及一個(gè)共享或私有的密鑰進(jìn)行簽名計(jì)算得到的。簽名確保了只有知道該密鑰的實(shí)體才能創(chuàng)建有效的JWT,并且任何人都可以驗(yàn)證JWT的完整性和來源的真實(shí)性。Ish28資訊網(wǎng)——每日最新資訊28at.com

生成簽名的計(jì)算公式如下:Ish28資訊網(wǎng)——每日最新資訊28at.com

HMACSHA256(  base64UrlEncode(header) + "." +  base64UrlEncode(payload),  secret)

算出簽名以后,把Header、Payload、Signature 三個(gè)部分拼成一個(gè)字符串,每個(gè)部分之間用"點(diǎn)"(.)分隔,這個(gè)字符串就是JWT 。Ish28資訊網(wǎng)——每日最新資訊28at.com

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwianRpIjoiMXBteXNldGd1amNvZGVuIiwiZXhwIjoxNTE2MjQyNjIyLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXX0.eW91cmUtYXV0aG9yaXphdGlvbi1zaWduYXR1cmU=

對于這段字符串,我們在JWT官網(wǎng)中,使用它的解碼器進(jìn)行解碼,就可以得到Header、Payload、Signature這三部分。Ish28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Ish28資訊網(wǎng)——每日最新資訊28at.com

如何基于JWT進(jìn)行身份驗(yàn)證?

JWT生成

服務(wù)器首先構(gòu)建JWT的Header和Payload,并分別進(jìn)行Base64編碼。使用Header中指定的簽名算法(比如HMAC SHA-256或RSA)對編碼后的Header和Payload進(jìn)行簽名,生成Signature。將Header、Payload和Signature連接在一起,形成完整的JWT字符串。Ish28資訊網(wǎng)——每日最新資訊28at.com

JWT發(fā)放

用戶通過用戶名/密碼登錄后,服務(wù)器驗(yàn)證用戶身份無誤,便生成JWT并將其返回給客戶端。客戶端可以將JWT存儲在瀏覽器的LocalStorage、SessionStorage中,或者作為Bearer Token放在Authorization請求頭中。Ish28資訊網(wǎng)——每日最新資訊28at.com

這里需要注意,將JWT存儲在瀏覽器的localStorage中,相較于存儲在Cookie中,可以降低CSRF(跨站請求偽造)的風(fēng)險(xiǎn)。因?yàn)镃SRF攻擊依賴于瀏覽器自動附帶在請求中的Cookie,而localStorage中的數(shù)據(jù)不會自動包含在普通的HTTP請求頭部。Ish28資訊網(wǎng)——每日最新資訊28at.com

至于攜帶JWT的方式,建議將JWT放在HTTP Header的Authorization字段中,采用Bearer Token的形式:Ish28資訊網(wǎng)——每日最新資訊28at.com

Authorization: Bearer <JWT>

這種做法允許在無狀態(tài)的RESTful API中方便地進(jìn)行身份驗(yàn)證,服務(wù)器可以根據(jù)請求頭中的JWT來驗(yàn)證請求發(fā)起者的身份和權(quán)限。同時(shí),這種方式也便于實(shí)現(xiàn)JWT的刷新與撤銷。Ish28資訊網(wǎng)——每日最新資訊28at.com

JWT使用

在后續(xù)的請求中,客戶端將JWT隨HTTP請求一起發(fā)送給服務(wù)器。服務(wù)器接收到JWT后,對其進(jìn)行解碼和驗(yàn)證Signature,如果Signature正確,則說明JWT未被篡改,并且仍處于有效期內(nèi)。根據(jù)Payload中的信息,服務(wù)器可以確定用戶身份以及相關(guān)權(quán)限,從而做出相應(yīng)處理。Ish28資訊網(wǎng)——每日最新資訊28at.com

JWT過期與刷新

JWT有一定的生命周期,過了指定的exp字段時(shí)間后,服務(wù)器不再接受該JWT。對于長時(shí)間交互的場景,可以設(shè)計(jì)Refresh Token機(jī)制,當(dāng)JWT即將過期時(shí),客戶端使用Refresh Token去服務(wù)器申請新的JWT,以延長用戶會話的有效期。Ish28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片Ish28資訊網(wǎng)——每日最新資訊28at.com

JWT安全性

JWT如何防止被篡改?

JWT通過簽名(Signature)來防止被篡改。數(shù)字簽名的機(jī)制確保了JWT的內(nèi)容一旦被篡改,服務(wù)端就能檢測出來,從而拒絕非法的請求。Ish28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)客戶端帶著JWT向服務(wù)器發(fā)送請求時(shí),服務(wù)器會先將接收到的JWT按.分割成Header、Payload和Signature三部分。服務(wù)器使用與生成簽名時(shí)相同的密鑰和算法,根據(jù)接收到的Header和Payload重新計(jì)算簽名。如果重新計(jì)算出的簽名與接收到的Signature一致,那么可以認(rèn)為JWT在傳輸過程中未被篡改;如果不一致,則說明JWT已被篡改。Ish28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)然,JWT通過這種方式防止被篡改的一個(gè)大前提就是,秘鑰(Secret Key)是安全的,如果秘鑰泄漏,那就可以更改Header、Payload,然后利用這個(gè)秘鑰生成一個(gè)Signature就可以了,那么就不安全了。所以,我們一定要確保服務(wù)端使用的密鑰是安全的,并且嚴(yán)格保密,不對外泄露。Ish28資訊網(wǎng)——每日最新資訊28at.com

如何加強(qiáng)JWT的安全性?

作為使用者,防止JWT被篡改的主要措施并不直接體現(xiàn)在客戶端的操作上,而是依賴于服務(wù)端的安全設(shè)計(jì)和實(shí)施。我們可以通過以下方面考慮,加強(qiáng)JWT的安全性:Ish28資訊網(wǎng)——每日最新資訊28at.com

1. 服務(wù)端安全策略:首先我們必須確保服務(wù)端使用的密鑰是安全的,并且嚴(yán)格保密,不對外泄露。密鑰用于簽署和驗(yàn)證JWT,一旦密鑰泄露,可能導(dǎo)致JWT被偽造或篡改。并且還要采用安全強(qiáng)度足夠高的簽名算法,例如HS256、RS256等,這些算法能有效地確保JWT的完整性。Ish28資訊網(wǎng)——每日最新資訊28at.com

2. 正確的簽名流程:確保所有簽發(fā)的JWT都經(jīng)過服務(wù)器端簽名,并且每次驗(yàn)證JWT時(shí)都要使用相同的密鑰和算法進(jìn)行驗(yàn)證。Ish28資訊網(wǎng)——每日最新資訊28at.com

3. 設(shè)置合理的Token有效期:設(shè)置JWT的有效期(exp claim)限制,避免JWT長時(shí)間有效,減少惡意攻擊者篡改JWT后繼續(xù)使用的機(jī)會。Ish28資訊網(wǎng)——每日最新資訊28at.com

4. 嚴(yán)謹(jǐn)?shù)纳矸蒡?yàn)證邏輯:在服務(wù)端驗(yàn)證JWT時(shí),除了驗(yàn)證簽名之外,還應(yīng)對Payload中的其他重要聲明(如用戶ID、權(quán)限、過期時(shí)間等)進(jìn)行校驗(yàn)。Ish28資訊網(wǎng)——每日最新資訊28at.com

5. 客戶端存儲方式:盡管JWT被篡改的風(fēng)險(xiǎn)主要集中在網(wǎng)絡(luò)傳輸階段,但在客戶端存儲JWT時(shí),推薦使用localStorage而非Cookie(尤其是考慮到防止CSRF攻擊),同時(shí)也可以考慮對敏感信息加密存儲。Ish28資訊網(wǎng)——每日最新資訊28at.com

JWT相較于Cookie和Session的優(yōu)缺點(diǎn)

JWT的優(yōu)點(diǎn)

JWT是無狀態(tài)的,這樣服務(wù)器不需要存儲會話狀態(tài)信息,減輕了服務(wù)器端的存儲負(fù)擔(dān),在分布式環(huán)境下使用JWT可以在集群內(nèi)的任何節(jié)點(diǎn)驗(yàn)證,無需保持會話狀態(tài)同步,JWT還可以輕易地在不同域名的服務(wù)之間傳遞,適用于微服務(wù)架構(gòu)和跨域應(yīng)用。因?yàn)樗怂斜匾挠脩粜畔ⅲ栽诜?wù)間跳轉(zhuǎn)時(shí)無需再次驗(yàn)證用戶身份,每個(gè)請求都包含了認(rèn)證所需要的所有信息,減少了服務(wù)器查詢數(shù)據(jù)庫或存儲服務(wù)以驗(yàn)證用戶狀態(tài)的次數(shù),從而提高了效率。Ish28資訊網(wǎng)——每日最新資訊28at.com

JWT的缺點(diǎn)

JWT中的數(shù)據(jù)默認(rèn)情況下是Base64編碼的,雖然可以加密但并非強(qiáng)制要求,這使得在不加密的情況下,JWT不適合存儲敏感信息。相比而言,Session存儲在服務(wù)器端,安全性更高。如果JWT被盜取,黑客可以在有效期內(nèi)持續(xù)使用,直到token過期或被撤銷。另外JWT的體積相對較大,特別是當(dāng)包含更多信息時(shí)。每次HTTP請求都需要攜帶JWT,可能會增加請求頭的大小,尤其是在移動網(wǎng)絡(luò)環(huán)境下,可能會對帶寬和流量有較大影響。并且由于JWT自帶有效期,當(dāng)用戶登出時(shí),由于JWT無法立即失效,所以只要JWT發(fā)放出去,除非在服務(wù)器端維護(hù)黑名單或使用可撤銷的Token機(jī)制(如JWT ID Token配合OpenID Connect協(xié)議),否則無法立即廢棄或更改Token中的權(quán)限信息。Ish28資訊網(wǎng)——每日最新資訊28at.com

JWT應(yīng)用場景

? 身份驗(yàn)證:JWT通常用于用戶登錄認(rèn)證,服務(wù)器在驗(yàn)證用戶憑據(jù)成功后,生成一個(gè)帶有用戶特定信息和過期時(shí)間的JWT,客戶端收到后,在后續(xù)請求中將其作為憑證發(fā)送給服務(wù)器,服務(wù)器僅需驗(yàn)證JWT的簽名即可確認(rèn)用戶身份,無需持久化存儲會話信息。Ish28資訊網(wǎng)——每日最新資訊28at.com

? 授權(quán):JWT可以攜帶權(quán)限聲明,服務(wù)器通過解析JWT中的聲明,決定用戶是否有權(quán)訪問特定資源或執(zhí)行某些操作。Ish28資訊網(wǎng)——每日最新資訊28at.com

? 單點(diǎn)登錄(SSO):由于JWT可以跨域使用,因此在多個(gè)子系統(tǒng)間輕松實(shí)現(xiàn)SSO功能,用戶在一個(gè)系統(tǒng)登錄后,其JWT可在多個(gè)系統(tǒng)間傳遞,實(shí)現(xiàn)無縫登錄體驗(yàn)。Ish28資訊網(wǎng)——每日最新資訊28at.com

在高并發(fā)、分布式、跨域及移動端場景下,JWT常因其實(shí)現(xiàn)的簡潔性和高效性而得到青睞,而在注重?cái)?shù)據(jù)安全性、復(fù)雜會話管理和易控制的場景下,Session可能會是更好的選擇。同時(shí),很多現(xiàn)代應(yīng)用采用了混合策略,結(jié)合兩者的優(yōu)勢來優(yōu)化用戶體驗(yàn)和系統(tǒng)安全性。Ish28資訊網(wǎng)——每日最新資訊28at.com

如何使用JWT?

在實(shí)際開發(fā)中,我們可以使用Spring Boot框架結(jié)合JWT來實(shí)現(xiàn)用戶身份驗(yàn)證。我們來實(shí)現(xiàn)一個(gè)簡單的示例。Ish28資訊網(wǎng)——每日最新資訊28at.com

我們引入JWT的依賴包:Ish28資訊網(wǎng)——每日最新資訊28at.com

<dependency>    <groupId>io.jsonwebtoken</groupId>    <artifactId>jjwt</artifactId>    <version>0.12.4</version></dependency>

創(chuàng)建JWT工具類

創(chuàng)建一個(gè)JWT工具類,用于生成和驗(yàn)證JWT令牌。這個(gè)類通常會包含生成JWT、解析JWT以及提取其中載荷信息的方法。Ish28資訊網(wǎng)——每日最新資訊28at.com

import io.jsonwebtoken.*;import io.jsonwebtoken.security.Keys;import io.jsonwebtoken.security.SecureDigestAlgorithm;import org.springframework.beans.factory.annotation.Value;import org.springframework.security.core.Authentication;import org.springframework.security.core.userdetails.User;import org.springframework.stereotype.Component;import javax.crypto.SecretKey;import java.util.Date;/** * @version 1.0 * @description: <p></p > * @author: 碼農(nóng)Academy * @create: 2024/4/18 14:39 */@Componentpublic class JwtTokenUtil {    @Value("${security.jwt.token.secret-key}")    private String secretKey;    /**過期時(shí)間*/    private static final long VALIDITY_IN_MILLISECONDS = 3600000; // 1h    /**     * 生成JWT     * @param authentication 當(dāng)前登陸用戶信息     * @return JWT     */    public String generateToken(Authentication authentication) {        User user = (User) authentication.getPrincipal();        Date now = new Date();        // 設(shè)置過期時(shí)間        Date expiryDate = new Date(now.getTime() + VALIDITY_IN_MILLISECONDS);        //指定加密算法        SecureDigestAlgorithm<SecretKey, SecretKey> algorithm = Jwts.SIG.HS256;        //密鑰實(shí)例        SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes());        return Jwts.builder()                .subject(user.getUsername())                .signWith(key, algorithm) //設(shè)置簽名使用的簽名算法和簽名使用的秘鑰                .expiration(expiryDate) //設(shè)置過期時(shí)間                .claim("username", user.getUsername()) //設(shè)置自定義負(fù)載信息                .compact();    }    /**     * 驗(yàn)證JWT     * @param authToken     * @return     */    public boolean validateToken(String authToken) {        try {            Jws<Claims> claimsJws = parseJWT(authToken);            claimsJws.getPayload();            return true;        } catch (MalformedJwtException | ExpiredJwtException | UnsupportedJwtException | IllegalArgumentException e) {            return false;        }    }    /**     * 解析jwt     * @param authToken 登陸token     * @return     */    public Jws<Claims> parseJWT(String authToken){        //密鑰實(shí)例        SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes());        return Jwts.parser()                .verifyWith(key)  //設(shè)置簽名的密鑰                .build()                .parseSignedClaims(authToken); //設(shè)置要解析的jwt    }    /**     * 從JWT中獲取用戶名     * @param token     * @return     */    public String getUsernameFromToken(String token) {        Jws<Claims> claimsJws = parseJWT(token);        return (String) claimsJws.getPayload().get("username", String.class);    }}

實(shí)現(xiàn)JWT過濾器

創(chuàng)建一個(gè)自定義的JWT過濾器,它負(fù)責(zé)檢查每個(gè)請求的Authorization header中的Bearer Token,并對其進(jìn)行驗(yàn)證。驗(yàn)證成功后,創(chuàng)建一個(gè)Authentication對象,并將其置于SecurityContext中。Ish28資訊網(wǎng)——每日最新資訊28at.com

import com.springboot.base.jwt.util.JwtTokenUtil;import org.springframework.security.authentication.AbstractAuthenticationToken;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.List;import java.util.stream.Collectors;/** * @version 1.0 * @description: <p></p > * @author: 碼農(nóng)Academy * @create: 2024/4/18 16:15 */public class JwtAuthenticationFilter extends OncePerRequestFilter {    private final UserDetailsService userDetailsService;    private final JwtTokenUtil jwtTokenUtil;    private static final String BEARER_PREFIX = "Bearer ";     public JwtAuthenticationFilter(UserDetailsService userDetailsService, JwtTokenUtil jwtTokenUtil) {          this.userDetailsService = userDetailsService;          this.jwtTokenUtil = jwtTokenUtil;     }    @Override    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {        String jwtToken = getTokenFromRequest(request);        if (jwtToken != null && jwtTokenUtil.validateToken(jwtToken)) {            String username = jwtTokenUtil.getUsernameFromToken(jwtToken);            UserDetails userDetails = userDetailsService.loadUserByUsername(username);            // 用于權(quán)限校驗(yàn)            List<GrantedAuthority> authorities = userDetails.getAuthorities().stream()                    .map(authority -> new SimpleGrantedAuthority(authority.getAuthority()))                    .collect(Collectors.toList());            AbstractAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(                    userDetails, null, authorities            );            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));            SecurityContextHolder.getContext().setAuthentication(authentication);        }else {            // 如果出現(xiàn)異常,可能是無效的Token,此處可記錄日志或做其他處理            System.out.println("沒有登陸。。。。。。");        }        filterChain.doFilter(request, response);    }    private String getTokenFromRequest(HttpServletRequest request) {        String authHeader = request.getHeader("Authorization");        if (authHeader != null && authHeader.startsWith(BEARER_PREFIX)) {            return authHeader.replace(BEARER_PREFIX, "");        }        return null;    }}

配置Spring Security

配置Spring Security以支持JWT身份驗(yàn)證。這通常涉及編寫自定義的JWT過濾器,用于攔截請求并在請求頭中提取JWT令牌進(jìn)行驗(yàn)證。過濾器會在驗(yàn)證通過后將用戶信息填充到Spring Security的上下文中。Ish28資訊網(wǎng)——每日最新資訊28at.com

import com.springboot.base.jwt.filter.JwtAuthenticationFilter;import com.springboot.base.jwt.util.JwtTokenUtil;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.config.http.SessionCreationPolicy;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;/** * @version 1.0 * @description: <p></p > * @author: 碼農(nóng)Academy * @create: 2024/4/18 16:11 */@Configuration@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {    @Autowired    private JwtTokenUtil jwtTokenUtil;    @Autowired    private UserDetailsService userDetailsService;    @Override    public void configure(HttpSecurity http) throws Exception {        http.csrf().disable()                .authorizeRequests((requests) -> requests                        .antMatchers("/user/login").permitAll() // 登錄接口公開                        .anyRequest().authenticated() // 其他接口需要驗(yàn)證                )                .addFilterBefore(new JwtAuthenticationFilter(userDetailsService, jwtTokenUtil), UsernamePasswordAuthenticationFilter.class) // 添加JWT過濾器                .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); // 關(guān)閉Session管理    }    @Override    @Bean    public AuthenticationManager authenticationManagerBean() throws Exception {        return super.authenticationManagerBean();    }    @Bean    public PasswordEncoder passwordEncoder() {        return new BCryptPasswordEncoder();    }}

在實(shí)現(xiàn)Spring Security的UserDetailsService的接口,用于登陸時(shí)查詢用戶信息,構(gòu)造Spring Security的User信息。Ish28資訊網(wǎng)——每日最新資訊28at.com

import com.springboot.base.jwt.login.RoleEntity;import com.springboot.base.jwt.login.UserEntity;import com.springboot.base.jwt.repository.UserRepository;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.userdetails.User;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;import org.springframework.stereotype.Service;import java.util.Collection;import java.util.List;import java.util.stream.Collectors;/** * @version 1.0 * @description: <p></p > * @author: 碼農(nóng)Academy * @create: 2024/4/18 16:22 */@Servicepublic class UserDetailsServiceImpl implements UserDetailsService {    private final UserRepository userRepository;    public UserDetailsServiceImpl(UserRepository userRepository) {        this.userRepository = userRepository;    }    @Override    public UserDetails loadUserByUsername(String username) {        // 根據(jù)用戶名查詢用戶實(shí)體        UserEntity userEntity = userRepository.findByUserName(username);        // 如果用戶不存在,則拋出異常        if (userEntity == null) {            throw new UsernameNotFoundException("User not found with username: " + username);        }        // 將用戶實(shí)體轉(zhuǎn)換為Spring Security可識別的UserDetails對象        User user = new User(userEntity.getUserName(),                userEntity.getPassword(), // 注意:此處假設(shè)password字段是已經(jīng)經(jīng)過加密處理過的                userEntity.getEnabled(),                true, true, true,                getAuthorities(userEntity.getRoleList()) // 獲取用戶的角色并轉(zhuǎn)換為GrantedAuthority列表        );        System.out.println(user.getPassword());        return user;    }    private Collection<? extends GrantedAuthority> getAuthorities(List<RoleEntity> roles) {        return roles.stream()                .map(role -> new SimpleGrantedAuthority(role.getRoleCode()))                .collect(Collectors.toList());    }}

上述使用Spring Security,如果有疑問的東西可以去查一下Spring Security的工作原理。Ish28資訊網(wǎng)——每日最新資訊28at.com

登陸接口

我們在定義一個(gè)登陸接口,登陸成功后返回jwt生成的token。Ish28資訊網(wǎng)——每日最新資訊28at.com

import com.springboot.base.jwt.request.LoginRequest;import com.springboot.base.jwt.response.JwtResponse;import com.springboot.base.jwt.util.JwtTokenUtil;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.authentication.BadCredentialsException;import org.springframework.security.authentication.DisabledException;import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;import org.springframework.security.core.Authentication;import org.springframework.security.core.AuthenticationException;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** * @version 1.0 * @description: <p></p > * @author: 碼農(nóng)Academy * @create: 2024/4/18 17:31 */@RestController@RequestMapping("/user")public class LoginController {    @Autowired    private JwtTokenUtil jwtTokenUtil;    @Autowired    private AuthenticationManager authenticationManager;    @PostMapping("/login")    public ResponseEntity<?> createAuthenticationToken(@RequestBody LoginRequest loginRequest) throws Exception {        // 創(chuàng)建基于用戶名密碼的Authentication請求對象        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(                loginRequest.getUserName(),                loginRequest.getPassword()        );        try {            // 使用AuthenticationManager進(jìn)行身份驗(yàn)證            Authentication authentication = authenticationManager.authenticate(authToken);            // 如果身份驗(yàn)證成功,SecurityContextHolder會存儲該Authentication對象            SecurityContextHolder.getContext().setAuthentication(authentication);            // 生成JWT Token或其他形式的授權(quán)憑證            String token = jwtTokenUtil.generateToken(authentication);            // 返回帶有Token的響應(yīng)            return ResponseEntity.ok(new JwtResponse(token));        } catch (BadCredentialsException ex) {            // 處理用戶名/密碼不正確等錯(cuò)誤情況            System.out.println("密碼不正確");            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");        } catch (DisabledException ex) {            // 處理賬戶被禁用等情況            System.out.println("處理賬戶被禁用");            return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Account is disabled");        } catch (AuthenticationException e) {            System.out.println("Authentication failed");            // 其他身份驗(yàn)證異常            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Authentication failed");        }    }}
import com.fasterxml.jackson.annotation.JsonCreator;import lombok.Data;/** * @version 1.0 * @description: <p></p > * @author: 碼農(nóng)Academy * @create: 2024/4/18 18:59 */@Datapublic class JwtResponse {    private String token;    private String type = "Bearer";    public JwtResponse(String token) {        this.token = token;    }    @JsonCreator    public static JwtResponse of(String token) {        return new JwtResponse(token);    }}

我們模擬一下登陸發(fā)起請求:Ish28資訊網(wǎng)——每日最新資訊28at.com

登陸成功,返回token。Ish28資訊網(wǎng)——每日最新資訊28at.com

給一個(gè)錯(cuò)誤密碼,登陸失敗:Ish28資訊網(wǎng)——每日最新資訊28at.com

我們將token設(shè)置到Authorization中,發(fā)起其他業(yè)務(wù)請求:Ish28資訊網(wǎng)——每日最新資訊28at.com

接口請求成功。Ish28資訊網(wǎng)——每日最新資訊28at.com

我們改變一下token值,在發(fā)起請求:Ish28資訊網(wǎng)——每日最新資訊28at.com

后臺打印token校驗(yàn)失敗,即未登錄。Ish28資訊網(wǎng)——每日最新資訊28at.com

結(jié)論

JWT(JSON Web Tokens)作為一種輕量級且靈活的身份驗(yàn)證和授權(quán)機(jī)制,在現(xiàn)代web服務(wù)及移動應(yīng)用中得到了廣泛應(yīng)用。它允許服務(wù)器端通過加密簽名的方式向客戶端發(fā)放安全的、自包含的令牌,這些令牌可以攜帶必要的用戶身份信息和權(quán)限聲明,而且由于其無需持久化存儲的特性,非常適合于微服務(wù)架構(gòu)下的無狀態(tài)通信場景。Ish28資訊網(wǎng)——每日最新資訊28at.com

總結(jié)起來,采用JWT進(jìn)行身份驗(yàn)證具有以下優(yōu)點(diǎn):Ish28資訊網(wǎng)——每日最新資訊28at.com

? 安全性: 通過密鑰簽名保證令牌的安全性,防止篡改。Ish28資訊網(wǎng)——每日最新資訊28at.com

? 高效性: 狀態(tài)less設(shè)計(jì)減少了服務(wù)器端存儲負(fù)擔(dān),提升了系統(tǒng)的可擴(kuò)展性和響應(yīng)速度。Ish28資訊網(wǎng)——每日最新資訊28at.com

? 跨域友好: JWT可輕松應(yīng)用于多個(gè)域名或子系統(tǒng)間的認(rèn)證需求。Ish28資訊網(wǎng)——每日最新資訊28at.com

? 自包含性: 令牌自身攜帶了足夠的用戶信息,減輕了服務(wù)器端查詢數(shù)據(jù)庫的頻率。Ish28資訊網(wǎng)——每日最新資訊28at.com

? 有效期可控: 可以在JWT中設(shè)置過期時(shí)間,從而控制用戶的登錄會話持續(xù)時(shí)間。Ish28資訊網(wǎng)——每日最新資訊28at.com

不過需要注意的是,JWT并非適用于所有場景,尤其是在敏感數(shù)據(jù)的處理上,因?yàn)橐坏┝钆票唤孬@,黑客們在有效期內(nèi)可以持續(xù)使用。因此,在實(shí)施JWT方案時(shí),應(yīng)充分考慮其適用范圍,并配合合適的刷新策略、黑名單機(jī)制以及其他安全措施,確保系統(tǒng)的整體安全性和用戶體驗(yàn)。Ish28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-84909-0.html快手二面:有了Cookie和Session 為什么還要JWT ?你說一下JWT的原理?

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 面試官:Spring Boot 中的監(jiān)視器是什么?不是監(jiān)聽器嘛

下一篇: 開放式耳機(jī)市場再迎力作 Shokz 韶音春季新品重磅發(fā)布

標(biāo)簽:
  • 熱門焦點(diǎn)
Top