# 轉載請留言聯系
什么是JWT?
Json web token (JWT), 是為了在網絡應用環境間傳遞聲明而執行的一種基於JSON的開放標准((RFC 7519).該token被設計為緊湊且安全的,特別適用於分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便於從資源服務器獲取資源,也可以增加一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用於認證,也可被加密。
JWT最普遍的一個作用就是用來保存用戶的登錄信息。
以前都用session保存用戶的登錄信息,為什么現在又需要用JWT呢?
-
回顧session
先回顧一下基於session保存用戶的登錄信息的原理:

session的數據一般存儲在redis上,儲存的格式一般是這樣:

所以,session有什么缺點呢?
- 這種模式最大的問題是,沒有分布式架構,無法支持橫向擴展。如果使用一個服務器,該模式完全沒有問題。但是,如果它是服務器集群或分布式結構的話,則需要一個統一的session數據庫庫來保存會話數據實現共享,這樣負載均衡下的每個服務器才可以正確的驗證用戶身份。
- sessionid儲存在cookies上面的,所以也要做CSRF防護。cookie如果被截獲,用戶就會很容易受到跨站請求偽造的攻擊。
- 單點登錄問題:難以適用於單點登錄(Single Sign On : 簡寫SSO)的場景
- 移動開發一般都不使用sessionid來保存登錄狀態
附:
什么是單點登錄(SSO)?
單點登錄就是登錄一次,可以訪問多個不同的子系統(不同的域名)。當你登錄了淘寶之后,打開天貓后就自動登錄,即使淘寶和天貓是不同的域名。如果沒有單點登錄的話,你登錄了淘寶,再登錄天貓,也是需要輸入賬號密碼登錄的。
-
JWT的優點
JWT的優點就是能解決上面session的缺點......最重要的是能有效地解決單點登錄問題。
-
JWT的驗證流程

流程:
1)用戶登錄成功后,服務器簽發jwt,里面儲存着用戶的id等資料,用於標記用戶的登錄狀態。注意!不能保存敏感信息,例如密碼這些,具體原因下面有說。
2)然后在響應報文傳送回去給客戶端。
3)客戶端收到之后,通過html5的 localStorage 或 sessionStorage 來保存JWT。
4)在下一次訪問的時候,通過請求頭把JWT帶上,服務端收到之后,會進行校驗,校驗有沒有修改過啊,有沒有過期啊等。
5)校驗通過之后,就可以成功登錄了。
-
JWT長什么樣子?
頭部.載荷.簽名
JWT示例:
- 頭部header
jwt的頭部承載兩部分信息:
- 聲明類型,這里是jwt
- 聲明加密的算法,通常直接使用 HMAC SHA256
完整的頭部就像下面這樣的JSON:
{
'typ': 'JWT',
'alg': 'HS256'
}
然后將頭部進行base64編碼, 構成了第一部分。BASE64后的結果:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
-
載荷payload
載荷就是存放有效信息的地方。這個名字像是特指飛機上承載的貨品,這些有效信息包含:
標准中注冊的聲明 (建議但不強制使用) :
- iss: jwt簽發者
- sub: jwt所面向的用戶
- aud: 接收jwt的一方
- exp: jwt的過期時間,這個過期時間必須要大於簽發時間
- nbf: 定義在什么時間之前,該jwt都是不可用的.
- iat: jwt的簽發時間
- jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。
其它聲明 :比如,用戶的相關信息或其他業務需要的必要信息
定義一個payload:
{
"user_name": "John Doe",
"user_id": 10}
BASE64后的結果:
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9注意:payload部分不能存放敏感信息,因為base64是可以解碼的。
-
簽名signature
JWT的第三部分是一個簽證(簽名)信息,即對前兩部分簽名后得到的一個字符串。
簽名:使用密鑰(SECRECT_KEY )對數據進行加密,得到了一個值(簽名)。
簽名的作用:防止數據篡改,客戶端傳給服務器的jwt如果被修改過,服務器驗簽(校驗)會不通過。
// javascript // header和payload部分用.連接起來 var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); // 使用指定的算法簽名 var signature = HMACSHA256(encodedString, 'secret'); // 簽名結果: TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

