什麼是JWT?javascript
Json web token (JWT), 是爲了在網絡應用環境間傳遞聲明而執行的一種基於JSON的開放標準((RFC 7519).該token被設計爲緊湊且安全的,特別適用於分佈式站點的單點登陸(SSO)場景。JWT的聲明通常被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便於從資源服務器獲取資源,也能夠增長一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用於認證,也可被加密。html
JWT最廣泛的一個做用就是用來保存用戶的登陸信息。html5
之前都用session保存用戶的登陸信息,爲何如今又須要用JWT呢?java
先回顧一下基於session保存用戶的登陸信息的原理:web
session的數據通常存儲在redis上,儲存的格式通常是這樣: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
將這三部分用 . 來拼接在一塊兒,就是一個JWT了。