JWT(JSON Web Token)是比較流行的跨域認證解決方案。
一般來説做單點登錄見常的方式是將登錄憑證持久化,各服務都向持久層請求數據,這樣內部多個應用系統就可以共享登錄狀態。另一種方式是服務端只生成相關憑證但不保存,客户端先請求生成憑證,然後每次請求時將這個憑證帶上,由服務端校驗這個憑證是否有效。JWT就是這種方案
JWT原理
JWT原理是,服務器認證以後,生成一個JSON對象,返給用户
{
"姓名":"張三",
"角色":"管理員",
"到期時間":"2018/7/1 12:30"
}
以後用户與服務端通信時,都要帶上這個數據(該會進行加密處理)服務端對這個數據進行校驗來判斷這個數據的有效性。
以下是JWT認證方式的一個簡圖
JWT的數據結構
實際的JWT類似下面的數據:
eyJhbGciOiJIUzI1NiJ9.eyJ2YWx1ZSI6eyJuYW1lIjoiIiwidXNlcklkIjoiNTkxMTciLCJhdmF0YXJVcmwiOiIifSwiZWZmIjoxNzE5NDgyMTg0NTY5fQ.tE5PntqYNJOs0LPWM-aslmL4XAgXdADMgwuJy7-qPk8
它是一個很長的字符中,中間使用.分隔成三部分,三部分內容依次如下:
- Header(頭部)
- Payload(負載)
- Signature(簽名)
Header部分
Header部分是一個JSON對象,描述JWT的元數據,示例:
{
"alg":"HS256",
"typ":"JWT"
}
alt屬性表示簽名的算法(algorithm),默認是HMAC SHA256;typ屬性表示這個令牌的類型,最後將上面的JSON對象使用Base64URL算法轉成字符串。
Payload
Payload部分也是一個JSON對象,用來存放實際需要傳遞的數據。JWT的7個官方字段:
iss(issuer):簽發人
exp(expiration time):過期時間
sub(subject):主題
aud(audience):受眾
nbf(Not Before):生效時間
iat(Issued At):簽發時間
jti(JWT ID):編號
除了上面的官方字段外,我們在這個部分還可以定義私有字段:
{
"sub":"123",
"name":"John Doe",
"admin":true
}
需要注意的是,JWT默認是不加密的,任何人都有可能讀取到,所以不要將秘密信息放在這個部分。
這個JSON對象也要使用Base64URL算法轉成字符串
Signature
Signature部分是對前兩部分的簽名,防止數據篡改
首先,需要指定一個密鑰,這個密鑰只有服務器才知道,不能泄露給用户,然後,使用Header裏指定的簽名算法(默認是HMAC SHA256)按照下面的公司生產簽名:
HMACSHA25(
base64UrlEncode(header)+"."+
base64UrlEncode(payload),
secret
)
算出簽名後,將Header、Payload、Signature三個部分拼成一個字符串,每個部分之間用.分隔,就可以返回給用户。
JWT的使用方式
客户端收到服務器返回的JWT,可以儲存在Cookie裏面,也可以儲存在localStorage,此後,客户端每次與服務器通信,都要帶上這個JWT。
JWT的幾個特點
- JWT不存儲任何數據,可使服務器免除session存取的壓力,同時在集羣機或多子站上面,也免除了session需要同步的煩惱。
- JWT默認是不加密的,但也可以在生成Token以後,再使用密鑰加密一次
- JWT的缺點是,由於服務端不保存session狀態,因此無法在使用過程中廢止某個token,或者更改token的權限,也就是説,一旦JWT簽發了,在到期之前就會始終有效,除非服務端部署額外邏輯
- JWT本身包含了認證信息,一旦泄露,任何人都可以獲得該令牌的所有權限,所以JWT的有效期應該設置得比較短
- 為了安全,JWT不建議使用HTTP協議明碼傳輸,要使用HTTPS傳輸