【深度知識】JSON Web令牌(JWT)的原理俘侠,流程和數(shù)據(jù)結(jié)構(gòu)

1. 摘要

JSON Web Token(縮寫 JWT)是目前最流行的跨域認證解決方案购撼,本文介紹它的原理,用法和詳細的數(shù)據(jù)結(jié)構(gòu)匕累。

2. JWT的定義

Json web token(JWT)是為了網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開發(fā)標(biāo)準(RFC 7519)陵刹,該token被設(shè)計為緊湊且安全的,特別適用于分布式站點的單點登陸(SSO)場景欢嘿。JWT的聲明一般被用來在身份提供者和服務(wù)提供者間傳遞被認證的用戶身份信息衰琐,以便于從資源服務(wù)器獲取資源,也可以增加一些額外的其它業(yè)務(wù)邏輯所必須的聲明信息炼蹦,該token也可直接被用于認證羡宙,也可被加密。

什么情況下使用JWT比較適合掐隐?
授權(quán):這是最常見的使用場景狗热,解決單點登錄問題。因為JWT使用起來輕便虑省,開銷小匿刮,服務(wù)端不用記錄用戶狀態(tài)信息(無狀態(tài)),所以使用比較廣泛探颈;
信息交換:JWT是在各個服務(wù)之間安全傳輸信息的好方法熟丸。因為JWT可以簽名,例如膝擂,使用公鑰/私鑰對兒 - 可以確定請求方是合法的虑啤。此外隙弛,由于使用標(biāo)頭和有效負載計算簽名,還可以驗證內(nèi)容是否未被篡改狞山。

3. JWT的原理和流程

3.1 跨域認證的問題

互聯(lián)網(wǎng)服務(wù)離不開用戶認證全闷。一般流程是下面這樣:
1、用戶向服務(wù)器發(fā)送用戶名和密碼萍启。
2总珠、服務(wù)器驗證通過后,在當(dāng)前對話(session)里面保存相關(guān)數(shù)據(jù)勘纯,比如用戶角色局服、登錄時間等等。
3驳遵、服務(wù)器向用戶返回一個 session_id淫奔,寫入用戶的 Cookie。
4堤结、用戶隨后的每一次請求唆迁,都會通過 Cookie,將 session_id 傳回服務(wù)器竞穷。
5唐责、服務(wù)器收到 session_id,找到前期保存的數(shù)據(jù)瘾带,由此得知用戶的身份鼠哥。

這種模式的問題在于,擴展性(scaling)不好看政。單機當(dāng)然沒有問題朴恳,如果是服務(wù)器集群,或者是跨域的服務(wù)導(dǎo)向架構(gòu)允蚣,就要求 session 數(shù)據(jù)共享菜皂,每臺服務(wù)器都能夠讀取 session。

舉例來說厉萝,A 網(wǎng)站和 B 網(wǎng)站是同一家公司的關(guān)聯(lián)服務(wù)』衅現(xiàn)在要求,用戶只要在其中一個網(wǎng)站登錄谴垫,再訪問另一個網(wǎng)站就會自動登錄章母,請問怎么實現(xiàn)?

一種解決方案是 session 數(shù)據(jù)持久化翩剪,寫入數(shù)據(jù)庫或別的持久層乳怎。各種服務(wù)收到請求后,都向持久層請求數(shù)據(jù)前弯。這種方案的優(yōu)點是架構(gòu)清晰蚪缀,缺點是工程量比較大秫逝。另外,持久層萬一掛了询枚,就會單點失敗违帆。
另一種方案是服務(wù)器索性不保存 session 數(shù)據(jù)了,所有數(shù)據(jù)都保存在客戶端金蜀,每次請求都發(fā)回服務(wù)器刷后。JWT 就是這種方案的一個代表。

3.2 JWT 的原理

JWT 的原理是渊抄,服務(wù)器認證以后尝胆,生成一個 JSON 對象,發(fā)回給用戶护桦,就像下面這樣含衔。
{
"姓名": "張三",
"角色": "管理員",
"到期時間": "2018年7月1日0點0分"
}
以后,用戶與服務(wù)端通信的時候二庵,都要發(fā)回這個 JSON 對象抱慌。服務(wù)器完全只靠這個對象認定用戶身份。為了防止用戶篡改數(shù)據(jù)眨猎,服務(wù)器在生成這個對象的時候,會加上簽名强经。

服務(wù)器就不保存任何 session 數(shù)據(jù)了睡陪,也就是說,服務(wù)器變成無狀態(tài)了匿情,從而比較容易實現(xiàn)擴展兰迫。

區(qū)別
(1) session 存儲在服務(wù)端占用服務(wù)器資源,而 JWT 存儲在客戶端
(1) session 存儲在 Cookie 中炬称,存在偽造跨站請求偽造攻擊的風(fēng)險
(2) session 只存在一臺服務(wù)器上汁果,那么下次請求就必須請求這臺服務(wù)器,不利于分布式應(yīng)用
(3) 存儲在客戶端的 JWT 比存儲在服務(wù)端的 session 更具有擴展性

3.3 JWT的認證流程圖

流程說明:
1玲躯,瀏覽器發(fā)起請求登陸据德,攜帶用戶名和密碼;
2跷车,服務(wù)端驗證身份棘利,根據(jù)算法,將用戶標(biāo)識符打包生成 token,
3朽缴,服務(wù)器返回JWT信息給瀏覽器善玫,JWT不包含敏感信息;
4密强,瀏覽器發(fā)起請求獲取用戶資料茅郎,把剛剛拿到的 token一起發(fā)送給服務(wù)器蜗元;
5,服務(wù)器發(fā)現(xiàn)數(shù)據(jù)中有 token系冗,驗明正身奕扣;
6,服務(wù)器返回該用戶的用戶資料毕谴;

3.4 JWT的6個優(yōu)缺點

1成畦、JWT默認不加密,但可以加密涝开。生成原始令牌后循帐,可以使用改令牌再次對其進行加密。
2舀武、當(dāng)JWT未加密方法是拄养,一些私密數(shù)據(jù)無法通過JWT傳輸。
3银舱、JWT不僅可用于認證瘪匿,還可用于信息交換。善用JWT有助于減少服務(wù)器請求數(shù)據(jù)庫的次數(shù)寻馏。
4棋弥、JWT的最大缺點是服務(wù)器不保存會話狀態(tài),所以在使用期間不可能取消令牌或更改令牌的權(quán)限诚欠。也就是說顽染,一旦JWT簽發(fā),在有效期內(nèi)將會一直有效轰绵。
5粉寞、JWT本身包含認證信息,因此一旦信息泄露左腔,任何人都可以獲得令牌的所有權(quán)限唧垦。為了減少盜用,JWT的有效期不宜設(shè)置太長液样。對于某些重要操作振亮,用戶在使用時應(yīng)該每次都進行進行身份驗證。
6鞭莽、為了減少盜用和竊取双炕,JWT不建議使用HTTP協(xié)議來傳輸代碼,而是使用加密的HTTPS協(xié)議進行傳輸撮抓。

4. JWT 的數(shù)據(jù)結(jié)構(gòu)

4.1 JWT消息構(gòu)成

一個token分3部分妇斤,按順序:

  • 頭部(header)
  • 載荷(payload)
  • 簽證(signature)
    對象為一個很長的字符串,字符之間通過"."分隔符分為三個子串。注意JWT對象為一個長字串站超,各字串之間也沒有換行符荸恕,一般格式為:xxxxx.yyyyy.zzzzz 。
    例如 yJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

4.2 頭部(header)

JWT的頭部承載兩部分信息:

  • 聲明類型死相,這里是jwt
  • 聲明加密的算法 通常直接使用 HMAC SHA256

JWT里驗證和簽名使用的算法融求,可選擇下面的:

JWS 算法名稱 描述
HS256 HMAC256 HMAC with SHA-256
HS384 HMAC384 HMAC with SHA-384
HS512 HMAC512 HMAC with SHA-512
RS256 RSA256 RSASSA-PKCS1-v1_5 with SHA-256
RS384 RSA384 RSASSA-PKCS1-v1_5 with SHA-384
RS512 RSA512 RSASSA-PKCS1-v1_5 with SHA-512
ES256 ECDSA256 ECDSA with curve P-256 and SHA-256
ES384 ECDSA384 ECDSA with curve P-384 and SHA-384
ES512 ECDSA512 ECDSA with curve P-521 and SHA-512

JWT的頭部描述JWT元數(shù)據(jù)的JSON對象參考:
{
"alg": "HS256",
"typ": "JWT"
}

代碼樣例如下:

// header Map
Map<String, Object> map = new HashMap<>();
map.put("alg", "HS256");
map.put("typ", "JWT");

4.3 載荷(payload)

Payload 部分也是一個 JSON 對象,用來存放實際需要傳遞的數(shù)據(jù)算撮。JWT 規(guī)定了7個官方字段生宛,供選用。

iss (issuer):簽發(fā)人
exp (expiration time):過期時間
sub (subject):主題
aud (audience):受眾
nbf (Not Before):生效時間
iat (Issued At):簽發(fā)時間
jti (JWT ID):編號

除以上默認字段外肮柜,我們還可以自定義私有字段陷舅,如下例:
{
"sub": "1234567890",
"name": "chongchong",
"admin": true
}
注意,JWT 默認是不加密的审洞,任何人都可以讀到莱睁,所以不要把秘密信息放在這個部分。
這個 JSON 對象也要使用 Base64URL 算法轉(zhuǎn)成字符串芒澜。
代碼樣例如下:

 JWT.create().withHeader(map) // header
                .withClaim("iss", "Service") // payload
                .withClaim("aud", "APP")
                .withIssuedAt(iatDate) // sign time
                .withExpiresAt(expiresDate) // expire time
                .withClaim("name", "cy") // payload
                .withClaim("user_id", "11222");

4.4 簽名(signature)

Signature 部分是對前兩部分的簽名仰剿,防止數(shù)據(jù)篡改。
首先痴晦,需要指定一個密鑰(secret)南吮。這個密鑰只有服務(wù)器才知道,不能泄露給用戶誊酌。然后部凑,使用 Header 里面指定的簽名算法(默認是 HMAC SHA256),按照下面的公式產(chǎn)生簽名术辐。

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

算出簽名以后,把 Header施无、Payload辉词、Signature 三個部分拼成一個字符串,每個部分之間用"點"(.)分隔猾骡,就構(gòu)成整個JWT對象TOKEN瑞躺, 就可以返回給用戶。

4.4.1 Base64URL算法

前面提到兴想,Header 和 Payload 串型化的算法是 Base64URL幢哨。這個算法跟 Base64 算法基本類似,但有一些小的不同嫂便。
JWT 作為一個令牌(token)捞镰,有些場合可能會放到 URL(比如 api.example.com/?token=xxx)。Base64 有三個字符+、/和=岸售,在 URL 里面有特殊含義践樱,所以要被替換掉:=被省略、+替換成-凸丸,/替換成_ 拷邢。這就是 Base64URL 算法。

4.5 JWT的用法

客戶端接收服務(wù)器返回的JWT屎慢,將其存儲在Cookie或localStorage中瞭稼。
此后,客戶端將在與服務(wù)器交互中都會帶JWT腻惠。如果將它存儲在Cookie中环肘,就可以自動發(fā)送,但是不會跨域妖枚,因此一般是將它放入HTTP請求的Header Authorization字段中廷臼。

Authorization: Bearer <token>

當(dāng)跨域時,也可以將JWT被放置于POST請求的數(shù)據(jù)主體中绝页。

5. JWT荠商、JWS、JWE的區(qū)別

1)JWT(JSON Web Tokens)续誉,jwt長度較小莱没,且可以使用URL傳輸(URL safe)。不想cookies只能在web環(huán)境起作用酷鸦。 JWT可以同時使用在web環(huán)境和RESTfull的接口饰躲。

2)對于開發(fā)者來說,JWT與另外兩種相近的標(biāo)準:JWS(JSON Web Signature)臼隔、JWE(JSON Web Encryption)嘹裂,容易引起混亂。

3)關(guān)于JWT的描述摔握,可以參考RFC7519(https://tools.ietf.org/html/rfc7519)的描述:
**JSON Web Token (JWT) **是一個間接地寄狼、URL安全的,表現(xiàn)為一組聲明氨淌,可以在雙方之間進行傳輸泊愧。一個JWT的聲明,是指經(jīng)過編碼后的一個JSON對象盛正,這個JSON對象可以是一個JSON Web Signature(JWS)結(jié)構(gòu)的荷載(payload)删咱,或者是一個JSON Web Encryption(JWE)結(jié)構(gòu)的明文。允許使用聲明進行數(shù)字簽名豪筝,或者通過一個Message Authentication Code(MAC)進行完整性保護可選擇是否加密痰滋。

簡單來說摘能,JWTs表現(xiàn)為一組被編碼為JWS and/or JWE結(jié)構(gòu)的JSON object的聲明(Claim).

換言之,一組JWT聲明(就是表現(xiàn)為JSON格式的Claims)被通過JWS結(jié)構(gòu)或者JWE結(jié)構(gòu)(或者同時使用兩種)發(fā)送即寡,決定于你如何去實現(xiàn)它徊哑。所以,當(dāng)你發(fā)送JWT給別人是聪富,它實際上是一個JWT荷載或者JWE荷載莺丑。JWS荷載更加常用。

4)關(guān)于JWS
顧名思義墩蔓,JWS模式對這個內(nèi)容進行了數(shù)字化簽名梢莽。這個內(nèi)容被用來存放JWT的聲明.服務(wù)端簽名出JWT并且發(fā)送到客戶端,并在用戶成功認證后進行應(yīng)答奸披。服務(wù)器期望客戶端在下次請求的時候?qū)WS作為請求的一部分昏名,發(fā)送回服務(wù)端。

如果我們處理的客戶端是欺騙者怎么辦呢阵面?這就是簽名(signature)需要出場的地方了轻局。簽名攜帶了完整的可驗證的信息。換句話說样刷,服務(wù)器可以確認仑扑,接收到的JWT聲明里的JWS是沒有經(jīng)過欺騙客戶端、中間者進行修改的置鼻。
服務(wù)端通過驗證消息的簽名來確闭蛞客戶端沒有修改聲明。如果服務(wù)端檢測到任何修改箕母,可以采取適當(dāng)?shù)膭幼?拒絕這次請求或者鎖定客戶端之類的)储藐。
客戶端同樣可以驗證簽名,為了做到這點嘶是,客戶端也需要服務(wù)端的secret(密鑰)(如果這個JWT簽名是HMAC算法),或者需要服務(wù)端對公鑰(如果這個WJT是數(shù)字化簽名)钙勃。
特別注意:對于JWS,荷載(聲明部分)沒有進行加密聂喇,所以辖源,不要發(fā)送任何敏感信息。

5)關(guān)于JWE
JWE模式會對內(nèi)容加密授帕,而不是簽名同木。JWT的聲明會被加密浮梢。因此JWE帶來了保密性跛十。JWE可以被簽名并附在JWS里。這樣的話就可以同時加密和簽名秕硝。因此得到了保密性(Confidentiality)芥映、完整性(Integrity)、可認證(Authentication)。

6)那么對于客戶端奈偏,如何分辨JWS或者JWE呢坞嘀?
JWS的Header與JWE的Header是不同的,可以通過檢查“alg”Header參數(shù)的值來區(qū)分惊来。如果這個值表現(xiàn)為一個數(shù)字簽名或者MAC的算法丽涩,或者是”none“,則它是一個JWS裁蚁。
如果它表現(xiàn)為一個 Key Encryption, Key Wrapping, Direct Key Agreement, Key Agreement with Key Wrapping, or Direct Encryption algorithm矢渊。則它是一個JWE。
還可以通過Header里的“enc”(encryption algorithm)是否存在來判斷枉证,如果"enc"這個成員存在的話說明是JWE矮男,否則的話就是JWS.

7.參考

(1)10分鐘了解JSON Web令牌(JWT)
https://baijiahao.baidu.com/s?id=1608021814182894637&wfr=spider&for=pc
(2)JWT的使用流程
https://blog.csdn.net/shmely/article/details/85915044
(3)JWT全面解讀、使用步驟
https://blog.csdn.net/achenyuan/article/details/80829401
(4)JSON Web Token 入門教程 -阮一峰
http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
(5)JWT(JSON Web Tokens)
https://www.cnblogs.com/zaixiuxing/p/6005968.html
(6)使用JWT實現(xiàn)單點登錄(完全跨域方案)
https://blog.csdn.net/weixin_42873937/article/details/82460997

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末室谚,一起剝皮案震驚了整個濱河市毡鉴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秒赤,老刑警劉巖猪瞬,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異倒脓,居然都是意外死亡撑螺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門崎弃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甘晤,“玉大人,你說我怎么就攤上這事饲做∠呋椋” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵盆均,是天一觀的道長塞弊。 經(jīng)常有香客問我,道長泪姨,這世上最難降的妖魔是什么游沿? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮肮砾,結(jié)果婚禮上诀黍,老公的妹妹穿的比我還像新娘。我一直安慰自己仗处,他們只是感情好眯勾,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布枣宫。 她就那樣靜靜地躺著,像睡著了一般吃环。 火紅的嫁衣襯著肌膚如雪也颤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天郁轻,我揣著相機與錄音翅娶,去河邊找鬼。 笑死好唯,一個胖子當(dāng)著我的面吹牛故觅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播渠啊,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼输吏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了替蛉?” 一聲冷哼從身側(cè)響起贯溅,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎躲查,沒想到半個月后它浅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡镣煮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年姐霍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片典唇。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡镊折,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出介衔,到底是詐尸還是另有隱情恨胚,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布炎咖,位于F島的核電站赃泡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏乘盼。R本人自食惡果不足惜升熊,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绸栅。 院中可真熱鬧级野,春花似錦、人聲如沸阴幌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矛双。三九已至渊抽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間议忽,已是汗流浹背懒闷。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留栈幸,地道東北人愤估。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像速址,于是被迫代替她去往敵國和親玩焰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容