电竞比分网-中国电竞赛事及体育赛事平台

分享

一步步帶你了解前后端分離利器之JWT

 漢無為 2019-03-05

來源:https://blog.csdn.net/xlgen157387/article/details/79191900

一、HTTP的無狀態(tài)性

HTTP 是無狀態(tài)協(xié)議,它不對之前發(fā)送過的請求和響應(yīng)的狀態(tài)進行管理。也就是說,無法根據(jù)之前的狀態(tài)進行本次的請求處理。假設(shè)要求登錄認(rèn)證的 Web 頁面本身無法進行狀態(tài)的管理(不記錄已登錄的狀態(tài)),那么每次跳轉(zhuǎn)新頁面不是要再次登錄,就是要在每次請求報文中附加參數(shù)來管理登錄狀態(tài)。

不可否認(rèn),無狀態(tài)協(xié)議當(dāng)然也有它的優(yōu)點。由于不必保存狀態(tài),自然可減少服務(wù)器的 CPU 及內(nèi)存資源的消耗。從另一側(cè)面來說,也正是因為 HTTP 協(xié)議本身是非常簡單的,所以才會被應(yīng)用在各種場景里。

二、Cookie 技術(shù)的引入

如果讓服務(wù)器管理全部客戶端狀態(tài)則會成為負(fù)擔(dān),保留無狀態(tài)協(xié)議這個特征的同時又要解決類似的矛盾問題,于是引入了 Cookie 技術(shù)。Cookie 技術(shù)通過在請求和響應(yīng)報文中寫入Cookie信息來控制客戶端的狀態(tài)。

Cookie會根據(jù)從服務(wù)器端發(fā)送的響應(yīng)報文內(nèi)的一個叫做Set-Cookie 的首部字段信息,通知客戶端保存 Cookie。當(dāng)下次客戶端再往該服務(wù)器發(fā)送請求時,客戶端會自動在請求報文中加入Cookie 值后發(fā)送出去。

1、沒有 Cookie 信息狀態(tài)下的請求(圖片來源《圖解HTTP》)

一步步帶你了解前后端分離利器之JWT

2、第 2 次以后(存有 Cookie 信息狀態(tài)) 的請求(圖片來源《圖解HTTP》)

一步步帶你了解前后端分離利器之JWT

3、詳細(xì)介紹Cookie 傳輸過程

一步步帶你了解前后端分離利器之JWT

服務(wù)器端發(fā)現(xiàn)客戶端發(fā)送過來的 Cookie 后, 會去檢查究竟是從哪一個客戶端發(fā)來的連接請求, 然后對比服務(wù)器上的記錄, 最后得到之前的狀態(tài)信息。

三、基于表單的認(rèn)證

目前用戶的認(rèn)證多半是基于表單的認(rèn)證,基于表單的認(rèn)證一般會使用 Cookie 來管理Session(Session會話,Session代表著服務(wù)器和客戶端一次會話的過程,直到Session失效(服務(wù)端關(guān)閉)或者客戶端關(guān)閉時結(jié)束)?;诒韱握J(rèn)證本身是通過服務(wù)器端的 Web應(yīng)用,將客戶端發(fā)送過來的用戶ID和密碼與之前登錄過的信息做匹配來進行認(rèn)證的。

但鑒于 HTTP 是無狀態(tài)協(xié)議, 之前已認(rèn)證成功的用戶狀態(tài)無法通過協(xié)議層面保存下來。 即無法實現(xiàn)狀態(tài)管理, 因此即使當(dāng)該用戶下一次繼續(xù)訪問,也無法區(qū)分他與其他的用戶。于是我們會使用Cookie 來管理 Session,以彌補 HTTP 協(xié)議中不存在的狀態(tài)管理功能。

一步步帶你了解前后端分離利器之JWT

簡單的來說就是,用戶在登錄的時候,會在Web服務(wù)器中開辟一段內(nèi)存空間Session用于保存用戶的認(rèn)證信息和其他信息,用戶登錄成功之后會通過Set-Cookie的首部字段信息,通知客戶端保存Cookie,而這Cookie保存的就是服務(wù)器端Session的ID,下次請求的時候客戶端會帶上該Cookie向服務(wù)器端發(fā)送請求,服務(wù)器端進行校驗,如果Session中保存的有該ID的Session就表示用戶認(rèn)證通過,否則失??!

一步步帶你了解前后端分離利器之JWT

四、Session存儲位置以及集群情況下的問題

Session 是存儲在Web服務(wù)器(例如:Tomcat)中的,并針對每個客戶端(客戶),通過SessionID來區(qū)別不同用戶的。Session是以Cookie技術(shù)或URL重寫實現(xiàn),默認(rèn)以Cookie技術(shù)實現(xiàn),服務(wù)端會給這次會話創(chuàng)造一個JSESSIONID的Cookie值。

但是一個顯著的問題就是,在集群模式下如果通過Nginx負(fù)載均衡的時候,如果有一個用戶登錄的時候請求被分配到服務(wù)器A上,登錄成功后設(shè)置的Session就會存放在服務(wù)器A上了,但是在服務(wù)器B上卻沒有該用戶的Session數(shù)據(jù),當(dāng)用戶再次發(fā)起一個請求的時候,此時請求如果被分配到服務(wù)器B上,則就不會查詢到該用戶的登錄狀態(tài),就會出現(xiàn)登錄失敗的情況!

一種可以想到的方式就是將多個Web服務(wù)器上存儲的Session統(tǒng)一存儲到某一存儲介質(zhì)中,保證進集群中的每一臺機器都可以看到所有相同Session數(shù)據(jù),這里的同步體現(xiàn)在所有的Session存儲在同一的存儲介質(zhì)里邊。

幸運的是我們常用的Tomcat容器已經(jīng)為我們提供了一個接口,可以讓我們實現(xiàn)將Session存儲到除當(dāng)前服務(wù)器之外的其他存儲介質(zhì)上,例如Redis等。

一步步帶你了解前后端分離利器之JWT

了解Spring Session的小伙伴可能都會知道Spring Session的本質(zhì)就是通過實現(xiàn)Tomcat提供的該接口將Session存儲到Redis中,以此來實現(xiàn)Session的統(tǒng)一存儲管理,對Spring Session有興趣的小伙伴可以參考往期的文章:

1、使用Redis存儲Nginx+Tomcat負(fù)載均衡集群的Session

2、使用Spring Session和Redis解決分布式Session跨域共享問題

3、Spring Session解決分布式Session問題的實現(xiàn)原理

五、小結(jié)與需求痛點

Session和Cookie的目的相同,都是為了克服HTTP協(xié)議無狀態(tài)的缺陷,但完成的方法不同。Session通過Cookie,在客戶端保存SessionID,而將用戶的其他會話消息保存在服務(wù)端的Session對象中,與此相對的,Cookie需要將所有信息都保存在客戶端。因此Cookie存在著一定的安全隱患,例如本地Cookie中保存的用戶名密碼被破譯,或Cookie被其他網(wǎng)站收集,例如:

  1. appA主動設(shè)置域B cookie,讓域B cookie獲取;
  2. XSS,在appA上通過JavaScript獲取document.cookie,并傳遞給自己的appB。

上述過程我們簡單的描述了Session的演進過程還有使用同步的方式解決Session在集群的時候出現(xiàn)的問題,但是我們意識到了使用Spring Session的方式來實現(xiàn)Session的同步是一件相對比較麻煩的事情,我們雖然使用Redis來進行同步,但是Redis并不是100%可靠的,我們需要對Redis搭建集群、進行主從同步復(fù)制、進行持久化等,顯然這是一件很復(fù)雜的事情,因此有沒有一種小而輕便的方式來實現(xiàn)我們的這種認(rèn)證需求!那就是JWT了!

除了上述我們遇到的問題之外,在目前前后端分離的大環(huán)境下經(jīng)常會遇到需要根據(jù)用戶來分配權(quán)限和顯示相對應(yīng)信息的問題,雖然傳統(tǒng)的Cookie和Session機制可以解決這個問題,但就通用性而言,JWT(JSON Web Token)相對來說更好。

看到這里很多小伙伴都已經(jīng)按捺不住了!那JWT到底是什么呢?

六、JWT是什么

Json web token (JWT),是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標(biāo)準(zhǔn)((RFC 7519)。該標(biāo)準(zhǔn)被設(shè)計為緊湊且安全的,一般被用來在身份提供者和服務(wù)提供者間傳遞被認(rèn)證的用戶身份信息,以便于從資源服務(wù)器獲取資源,也可以增加一些額外的其它業(yè)務(wù)邏輯所必須的聲明信息。當(dāng)然該標(biāo)準(zhǔn)也可直接被用于認(rèn)證,也可被加密。

JWT的幾個特點:

1、由于它們的尺寸較小,JWT可以通過URL,POST參數(shù)或HTTP頭部發(fā)送。 另外,尺寸越小意味著傳輸速度越快。

2、有效載荷包含有關(guān)用戶的所有必需信息,避免了多次查詢數(shù)據(jù)庫的需要。

JWT的使用場景:

1、驗證

這是使用JWT最常見的情況。 一旦用戶登錄,每個后續(xù)請求將包括JWT。它將允許用戶訪問該令牌允許的路由,服務(wù)和資源。 單點登錄是當(dāng)今廣泛使用JWT的一項功能,因為它的開銷很小,而且能夠輕松地跨不同域使用。

2、信息交換

JWT是在各方之間安全傳輸信息的好方法, 因為JWT可以被簽名(例如使用公鑰/私鑰對進行簽名)。所以你可以確定發(fā)件人是他們說的那個人。 此外,由于使用頭部(header)和有效載荷(payload)計算簽名,因此您還可以驗證內(nèi)容是否未被篡改。

七、JWT的結(jié)構(gòu)說明

JWT包含三個由點(.)分隔的部分,它們是:

  1. 頭部(header)
  2. 有效負(fù)載(payload)
  3. 簽名(signature)

因此,JWT通??雌饋砣缦滤?

xxxxx.yyyyy.zzzzz

1、頭部(header)

頭部(header)通常由兩部分組成:令牌的類型(即JWT)和正在使用的散列算法(如HMAC SHA256或RSA)。如下所示:

一步步帶你了解前后端分離利器之JWT

然后,將這個JSON用Base64編碼,形成JWT的第一部分。

2、有效負(fù)載(payload)

令牌的第二部分是包含聲明的有效載荷。 聲明是關(guān)于實體(通常是用戶)和附加元數(shù)據(jù)的聲明。 有三種類型的聲明:

  1. 標(biāo)準(zhǔn)中注冊的聲明;
  2. 公開聲明;
  3. 私人聲明;

(1)標(biāo)準(zhǔn)中注冊的聲明:這是一組預(yù)先定義的聲明,這些聲明不是強制性的,但建議提供一套有用的,可互操作的聲明。 如下:

iss: jwt簽發(fā)者sub: jwt所面向的用戶aud: 接收jwt的一方exp: jwt的過期時間,這個過期時間必須要大于簽發(fā)時間nbf: 定義在什么時間之前,該jwt都是不可用的.iat: jwt的簽發(fā)時間jti: jwt的唯一身份標(biāo)識,主要用來作為一次性token,從而回避重放攻擊。

注意:聲明名稱只有三個字符長,因為JWT是緊湊的。

(2)公開聲明:這些可以由使用JWT的人員隨意定義。 但為避免沖突,應(yīng)在IANA JSON Web令牌注冊表中定義它們,或者將其定義為包含防沖突命名空間的URI。

(3)私人聲明:這是為了共享使用它們的當(dāng)事方之間共享信息而創(chuàng)建的聲明,既不是登記聲明,也不是公開聲明。

示例如下:

一步步帶你了解前后端分離利器之JWT

然后將有效載荷進行Base64編碼,以形成JSON Web令牌的第二部分。

3、簽名(signature)

要創(chuàng)建簽名部分,您必須采用頭部(header),有效載荷(payload),密鑰(secret),以及頭部中指定的算法。例如,如果你想使用HMAC SHA256算法,簽名將按以下方式創(chuàng)建:

一步步帶你了解前后端分離利器之JWT

簽名通常用于驗證JWT的發(fā)件人是誰,并JWT在傳送的過程中不被篡改。

注意:上圖紅框中的secret是保存在服務(wù)器端的,JWT的簽發(fā)生成也是在服務(wù)器端的,secret就是用來進行JWT的簽發(fā)和jwt的驗證,所以,它就是你服務(wù)端的私鑰,在任何場景都不應(yīng)該流露出去。一旦客戶端得知這個secret,那就意味著客戶端是可以自我簽發(fā)jwt了。

4、案例演示

下面顯示了一個登錄請求成功之后服務(wù)端返回的Token,它由編碼頭部(header)、編碼有效載荷(payload)和簽名(signature)通過(.)拼接而成:

一步步帶你了解前后端分離利器之JWT

一步步帶你了解前后端分離利器之JWT

如果需要,你可以使用jwt.io的Debugger工具,來編碼、驗證和生成JWT。操作界面如下:

一步步帶你了解前后端分離利器之JWT

八、JWT的工作原理

在身份驗證中,當(dāng)用戶使用他們的憑證(如用戶名、密碼)成功登錄時,后臺服務(wù)器將返回一個token,前端接收到這個token將其保存在本地(通常在本地存儲中,也可以使用Cookie,但不是傳統(tǒng)方法中創(chuàng)建會話,服務(wù)器并返回一個cookie)。下次用戶想要訪問受保護的路由或資源時,就將本地保存的token放在頭部Header中發(fā)送到后臺服務(wù)器。服務(wù)器接收到請求,檢查頭部中token的存在,如果存在就允許訪問受保護的路由或資源,否則就不允許。如下所示:

一步步帶你了解前后端分離利器之JWT

一般默認(rèn)的Value是以“Bearer ”開始,注意這里的Bearer之后有一個空格,以便后端進行分割。

這是一種無狀態(tài)身份驗證機制,因為用戶狀態(tài)永遠(yuǎn)不會保存在服務(wù)器內(nèi)存中。 由于JWT是獨立的,所有必要的信息都在那里,所以減少了多次查詢數(shù)據(jù)庫的需求。

一步步帶你了解前后端分離利器之JWT

九、總結(jié)

1、優(yōu)點

(1)因為Json的通用性,所以JWT是可以進行跨語言支持的,像Java、JavaScript、NodeJS、PHP等很多語言都可以使用。

(2)因為有了payload部分,所以JWT可以在自身存儲一些其他業(yè)務(wù)邏輯所必要的非敏感信息。

(3)便于傳輸,JWT的構(gòu)成非常簡單,字節(jié)占用很小,所以它是非常便于傳輸?shù)摹?/p>

(4)它不需要在服務(wù)端保存會話信息, 所以它易于應(yīng)用的擴展

2、安全相關(guān)

(1)不應(yīng)該在JWT的payload部分存放敏感信息,因為該部分是客戶端可解密的部分。

(2)保護好secret私鑰,該私鑰非常重要。

(3)如果可以,請使用HTTPS協(xié)議,不!是務(wù)必使用HTTPS!

十、文末彩蛋

后續(xù)會有兩至三篇文章介紹JWT的使用和JWT的優(yōu)缺點以及如何保證token的安全性等,敬請期待!

參考文章:

1、https://www./?p=362

2、https://www./?p=384

3、服務(wù)器前后端分離之JWT用戶認(rèn)證

4、部分截圖和內(nèi)容參考《圖解HTTP》

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多