什么是 JWT ?
JWT 全稱為 Json Web Token,是(shi)一(yi)個開(kai)放的(de)行業標準(RFC 7519),它定義(yi)了一(yi)種簡潔的(de)、自包含的(de)協議(yi)格式,用于在通信雙方傳遞(di) Json 對象,傳遞(di)的(de)信息經過數字簽(qian)名(ming),可以被(bei)驗(yan)證和信任。
什么時候使用 JWT ?
JWT 用(yong)途廣泛,例如 OAuth2、用(yong)戶授(shou)權(quan)、服(fu)務器(qi)(qi)通信(xin)鑒權(quan)等。比如在(zai)用(yong)戶授(shou)權(quan)的(de)場景中,服(fu)務器(qi)(qi)端(duan)可在(zai)用(yong)戶登錄后生成符合 JWT 規范的(de) AccessToken,并發送回用(yong)戶端(duan),之后用(yong)戶端(duan)可攜帶這個(ge) AccessToken 向服(fu)務器(qi)(qi)請求授(shou)權(quan)資源。
JWT 里有什么?
我們先(xian)來看(kan)看(kan) 標準的 JWT 長什么樣:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
可(ke)見,JWT 包含三段信(xin)息(xi),信(xin)息(xi)之間使(shi)用點號(.)分隔。
這三(san)段(duan)信(xin)息分(fen)別為頭部(bu)(Header)、載荷(he)(Payload)、簽名(Signature),下面我們(men)來(lai)說說這幾部(bu)分(fen)信(xin)息。
頭部(Header)
頭部信息為(wei) Base64 編碼(ma)的字(zi)符(fu)串(chuan),解碼(ma)后為(wei) Json 格式的字(zi)符(fu)串(chuan),示例如(ru)下:
{
"alg": "HS256",
"typ": "JWT"
}
該部分包含兩個信息:當前 JWT 使用的(de)簽名算法,比如 HMAC SHA256 或者 RSA,當前 JWT的(de)類型(xing),即 JWT。
載荷(Payload)
載(zai)荷跟頭(tou)部信息一樣,也(ye)是為 Base64 編碼(ma)的字符串,解碼(ma)后(hou)示例如下:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
該部分包含 token 的信息(claims),這里包含一些約定的字段以及 JWT 生成時生產方自定義的字段,其中,約定的字段是非必須的,但是 JWT 規范中推薦攜帶上。規范中約定的字段有: iss(生成方)、exp(過期時間)、sub(主體)、iat(生成時間)等,具體可查看 JWT規范約定字段說明。自定義(yi)(yi)字段(duan)(duan)則可由生(sheng)成方定義(yi)(yi),字段(duan)(duan)名(ming)稱不要(yao)(yao)和規范約(yue)定的字段(duan)(duan)沖突就(jiu)行。需(xu)要(yao)(yao)注(zhu)意的是不要(yao)(yao)在這(zhe)部分信(xin)(xin)(xin)息中存放(fang)敏感信(xin)(xin)(xin)息,因為這(zhe)些信(xin)(xin)(xin)息是沒有加密(mi)的,只(zhi)要(yao)(yao)拿到(dao)(dao) jwt 使用 Base64 解碼就(jiu)能獲取到(dao)(dao)。
簽名(Signature)
簽名(ming)部分用(yong)于信息的接收方確認當前 JWT 的合法性。要創建簽名(ming),你(ni)需要用(yong)到頭部、載荷(he)和(he)(he)密鑰(yao),首先將簽名(ming)方法寫在頭部信息里(li),然后對頭部和(he)(he)載荷(he)信息進(jin)行簽名(ming)。舉個(ge)例子,如果使用(yong) HMAC SHA256 算法,則該簽名(ming)可以通過以下方式生成:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
簽名可(ke)以(yi)保證 JWT 在(zai)傳輸(shu)的過程中(zhong)沒有被篡改,還有如(ru)果使(shi)用 RSA 做簽名,也(ye)可(ke)驗證 JWT 是否真的是生成者發來(lai)的,具有防(fang)抵(di)賴性。
為什么使用 JWT?
首(shou)先,JWT 由 Base64-URL 字符串并以點號(.)組成,非常適合在(zai) HTML 和 HTTP 環境中傳輸和解析(xi),Json 格式相對于 XML 也顯得更加緊(jin)湊和簡(jian)潔。同時,JWT 在(zai)傳輸過(guo)程(cheng)是(shi)無狀態(tai)的,更契(qi)合當前(qian)分(fen)布式應用場景。
JWT 如何使用?
在(zai)用(yong)戶(hu)(hu)鑒權場景中,當用(yong)戶(hu)(hu)使用(yong)賬號密碼等方式成(cheng)功登錄后(hou)(hou),服(fu)務(wu)端為當前用(yong)戶(hu)(hu)生(sheng)成(cheng)一個(ge)(ge) JWT 并返回,至此(ci)之后(hou)(hou),這個(ge)(ge) JWT 即為用(yong)戶(hu)(hu)的(de)鑒權標識(shi),后(hou)(hou)續服(fu)務(wu)端通過驗(yan)證 JWT 的(de)合法性判(pan)斷是否信(xin)任用(yong)戶(hu)(hu)的(de)請(qing)求。
需要(yao)注意(yi)的是,服務端需要(yao)為這個 JWT 設置一個過期(qi)時間,以免 JWT 泄露造成安全問題。還有就是不(bu)要(yao)在 JWT 中存放敏(min)感信息,因(yin)為 JWT 并(bing)不(bu)會(hui)做數據加密。
當用戶想要訪問受保護的(de)資源時,必須(xu)在(zai)請求中攜(xie)帶 JWT,通常(chang)的(de)做法(fa)是在(zai) HTTP 頭 Authorization 中使用 Bearer 協議,內容如下所(suo)示:
Authorization: Bearer <token>
這是一種(zhong)無狀態的鑒權機制,服務(wu)端通過校驗 Authorization 頭中的 JWT,如(ru)果存在(zai),則這個(ge)用戶可以訪問(wen)受保護的資源(yuan),如(ru)果這個(ge) JWT 包(bao)含一些必要的用戶信息,這個(ge)方式在(zai)某些情(qing)況(kuang)下還(huan)可以減少(shao)從數據庫讀取用戶信息的次數,提升訪問(wen)速度。
使用 Header 傳輸(shu) JWT,你要(yao)注(zhu)意(yi)不要(yao)存放過(guo)多的(de)信息到 JWT,這會(hui)導致(zhi) JWT 過(guo)于(yu)臃(yong)腫,影響傳輸(shu)速(su)度(du),甚(shen)至還有一些服務器會(hui)限制 Header 的(de)長度(du)不超過(guo) 8KB,真的(de)要(yao)存儲這么多信息的(de)話,請考慮(lv)使用別的(de)方(fang)案。
總結
在文章(zhang)中我(wo)們了(le)解了(le)什(shen)么(me)是 JWT、JWT 的(de)(de)(de)組(zu)成及原理(li)以(yi)及如何使用(yong)(yong)(yong)(yong) JWT,JWT 提供一個簡潔并(bing)且保證安(an)全(quan)的(de)(de)(de)規范(fan)用(yong)(yong)(yong)(yong)于信息的(de)(de)(de)傳輸(shu),它比基(ji)于 XML 的(de)(de)(de) SAML 更加緊(jin)湊和(he)(he)(he)簡潔,更加適用(yong)(yong)(yong)(yong)于 HTML 和(he)(he)(he) HTTP 環境的(de)(de)(de)傳輸(shu)和(he)(he)(he)解析,在安(an)全(quan)方面,JWT 使用(yong)(yong)(yong)(yong)自洽的(de)(de)(de)簽名算(suan)法(fa)(fa),可以(yi)使用(yong)(yong)(yong)(yong)相對簡單的(de)(de)(de)對稱算(suan)法(fa)(fa)以(yi)及更高安(an)全(quan)性的(de)(de)(de)非對稱公(gong)私鑰(yao)算(suan)法(fa)(fa)。JWT 在用(yong)(yong)(yong)(yong)戶鑒權、信息傳輸(shu)及交換等場(chang)景具有很大的(de)(de)(de)發(fa)揮空間。