What is Json Web Token
根據(jù)官網(wǎng)的定義,JWT 是一套開放的標準(RFC 7519),它定義了一套簡潔的(compact)、自包含的(self-contained)方案,來讓我們安全地在客戶端和服務器之間傳遞 JSON 格式的信息。
Advantages
- 體積小,因而傳輸速度快
- 傳輸方式多樣,可以通過 URL/POST 參數(shù)/HTTP 頭部 等方式傳輸
- 嚴謹?shù)慕Y構化。它自身(在 payload 中)就包含了所有與用戶相關的驗證消息,如用戶可訪問路由、訪問有效期等信息,服務器無需再去連接數(shù)據(jù)庫驗證信息的有效性,并且 payload 支持為你的應用而定制化
- 支持跨域驗證,多應用于單點登錄。
單點登錄(Single Sign On):在多個應用系統(tǒng)中,用戶只需登陸一次,就可以訪問所有相互信任的應用。
WHY JWT
除了上面說到的優(yōu)點之外,相比傳統(tǒng)的服務端驗證, JWT 還有以下優(yōu)點。
- 充分依賴無狀態(tài) API ,契合 RESTful 設計原則
- 易于實現(xiàn) CDN,將靜態(tài)資源分布式管理
- 驗證解耦,無需使用特定的身份驗證方案, token 可以在任何地方生成
- 比 cookie 更支持原生移動端應用
- 關于狀態(tài)
首先我們先看一下,什么是狀態(tài),什么是有狀態(tài)與無狀態(tài)。
狀態(tài):請求的狀態(tài)是 client 與 server 交互過程中,保存下來的相關信息,客戶端的保存在 page/request/session/application 或者全局作用域中,而 server 的一般存在 session 中。
有狀態(tài) API:server 保存了 client 的請求狀態(tài), server 會通過 client 傳遞的 sessionID 在其 session 作用域內(nèi)找到之前交互的信息并應答。
無狀態(tài) API:無狀態(tài)是 RESTful 架構設計的一個非常主要的原則。無狀態(tài) API 的每一個請求都是獨立的,它要求由客戶端保存所有需要的認證信息,每次發(fā)請求都要帶上自己的狀態(tài),以 url 的形式提交包含了 cookies 等狀態(tài)的數(shù)據(jù)。
JWT 就很好地體現(xiàn)了無狀態(tài)原則。用戶登陸之后,服務器會返回給他一個 token,由他保存在本地,在這之后的對服務器的訪問都要帶上這串 JWT ,來獲得訪問服務器相關路由、服務及資源的權限。比如單點登錄就比較多地使用了 JWT,因為它的體積小,并且簡單處理(使用 HTTP 頭帶上 Bearer 屬性 + token )就可以支持跨域操作。
分布式管理
在傳統(tǒng)的 session 驗證中,服務端必須保存 session ID,用于與用戶傳過來的 cookie 驗證。而在一開始保存 session ID 時, 只會保存在一臺服務器上,所以只能由一個 server 應答,就算其他服務器有空閑也無法應答,因此也利用不到分布式服務器的優(yōu)點。
而 JWT 依賴的是在客戶端本地保存驗證信息,不需要利用服務器保存的信息來驗證,所以任意一臺服務器都可以應答,服務器的資源也被較好地利用。驗證解耦
只要擁有生成 token 所需的驗證信息,在何處都可以調(diào)用 token 生成接口,無需繁瑣的耦合的驗證操作,可謂是一次生成,永久使用。對原生應用的支持(我對移動端開發(fā)不夠深入,這點不是很清楚)
原生的移動應用對 cookie 與 session 的支持不夠好,而對 token 的方式支持較好。
除此之外,JWT 的可靠的結構化的標準,也是我們選擇它的一大原因。特別是使用 nodejs 開發(fā)時,嗯,node 大法好!
client 使用 JWT 與 server 交互的過程

首先,擁有某網(wǎng)站賬號的某 client 使用自己的賬號密碼發(fā)送 post 請求 login,由于這是首次接觸,server 會校驗賬號與密碼是否合法,如果一致,則根據(jù)密鑰生成一個 token 并返回,client 收到這個 token 并保存在本地的 localStorage。在這之后,需要訪問一個受保護的路由或資源時,而只要附加上你保存在本地的 token(通常使用 Bearer 屬性放在 Header 的 Authorization 屬性中),server 會檢查這個 token 是否仍有效,以及其中的校驗信息是否正確,再做出相應的響應。
JWT 由三部分組成:Header/Payload/Signature
// Header
{
"alg": "HS256",
"type": "JWT"
}
// Payload
{
// reserved claims
"iss": "a.com",
"exp": "1d",
// public claims
"http://a.com": true,
// private claims
"company": "A",
"awesome": true
}
// $Signature
HS256(Base64(Header) + "." + Base64(Payload), secretKey)
JWT = {Base64(Header), Base64(Payload), $Signature}
第一部分是 Header。首先聲明一個 JSON 對象,對象里有一個 type 屬性,值為 JWT ,以及 alg 屬性,值為 HS256,表明最終使用的加密算法是 HS256。
第二部分是 Payload Claim。這一部分被定義為實體的狀態(tài),就像 token 自身附加元數(shù)據(jù)一樣,claim 包含我們想要傳輸?shù)男畔?,以及用于服務器驗證的信息,一般有 reserved/public/private 三類。
第三部分是 Signature。它由前面在 Header 指定的算法 HS256 加密兩個參數(shù)構成,第一個參數(shù)是經(jīng)過編碼的 Header 與經(jīng)過編碼的 Payload 通過 . 連接之后的字符串,第二個參數(shù)是生成的密鑰,會由服務器保存。每次服務器接收到 token 之后,也是先解密出用于驗證的用戶信息以及密鑰,再與自己保存的密鑰對比是否相同,以此來驗證用戶的身份。
寫完這么一大篇真是好累…還想繼續(xù)深挖一下 JWT 具體的應用、服務端如何驗證、JWT 使用 cookie 存儲好還是 HTML5 Web Storage 好的,剩下的只能留在下回分解啦。。
感謝以下參考文章:
Json Web Token Introduction
使用Json Web Token設計Passport系統(tǒng)
深入RESTful無狀態(tài)原則