使用Json Web Token設計Passport系統

1、Token Auth機制

基於Token的身份驗證是無狀態的,咱們不將用戶信息存在服務器或Session中。html

相比原始的Cookie+Session方式,更適合分佈式系統的用戶認證,繞開了傳統的分佈式Session一致性等問題。前端

基於Token的身份驗證的主流程以下:java

用戶經過用戶名和密碼發送請求;
程序驗證;
程序返回一個簽名的token 給客戶端;
客戶端儲存token,而且每次用於每次發送請求。git

2、相比Cookie認證的優點

支持跨域跨站點訪問:web

Cookie是不容許垮域訪問的,能夠經過設置頂級域名的方式實現部分跨域,可是跨站點的訪問仍然不支持,
若是使用Token機制,就能夠經過HTTP頭傳輸用戶認證信息,從而更好的實現跨域跨站點。算法

無狀態:json

Token機制在服務端不須要存儲session信息,Token自身包含了登陸用戶的信息,只須要在客戶端的cookie或本地介質存儲狀態信息;跨域

去耦:不須要綁定到一個特定的身份驗證方案。Token能夠在任何地方生成,只要在你的API被調用的時候,你能夠進行Token生成調用便可;瀏覽器

更適用於移動應用:緩存

當客戶端是原生應用時,Cookie是不被支持的,雖然目前Webview的方式能夠解決Cookie問題,

可是顯然採用Token認證機制會簡單得多;

安全性更強:

由於再也不依賴於Cookie,因此你就不須要考慮對CSRF(跨站請求僞造)的防範;

標準化易擴展:

能夠採用標準化的 JSON Web Token (JWT),對之後系統接入Node等純前端開發更便捷;

相比Session一致性提升性能:

相比服務端保存Session一致性信息,並查詢用戶登陸狀態,通常來講Token的驗證過程(包含加密和解密),性能開銷會更小。

3、JSON Web Token標準的設計

JWT 標準的 Token 有三個部分:

header.payload.signature

三個部分中間用點分隔開,而且都使用 Base64 編碼,因此生成的 Token 相似這樣:

ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9.ewogImlzcyI6ICJjaGJsb2dzLmNvbSIsCiAiZXhwIjogIjE0NzA3MzAxODIiLAogInVpZCI6ICIxMjM0NWFiY2RlIiwKfQ.9q2eq8sa374ao2uq9607r6qu6

(1)Header報頭

header 部分主要包括兩部分,一個是 Token 的類型,另外一個是使用的算法,
好比下面類型就是 JWT,使用的算法是 HS256。

{
"typ": "JWT",
"alg": "HS256"
}

Header內容要用 Base64 的形式編碼,因此就變成這樣:
ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9

(2)Payload載荷部分

Payload 裏面是 Token 的具體內容,這部份內容能夠自定義,JWT有標準字段,也能夠添加其它須要的內容。
標準字段:
iss:Issuer,發行者
sub:Subject,主題
aud:Audience,觀衆
exp:Expiration time,過時時間
nbf:Not before
iat:Issued at,發行時間
jti:JWT ID

這是一個典型的payload信息,包含了發行者(網站)、過時時間和用戶id:
{
"iss": "chblogs.com",
"exp": "1470730182",
"uid": "12345abcde",
}

這部份內容一樣要用Base64 編碼,生成編碼相似以下格式:

ewogImlzcyI6ICJjaGJsb2dzLmNvbSIsCiAiZXhwIjogIjE0NzA3MzAxODIiLAogInVpZCI6ICIxMjM0NWFiY2RlIiwKfQ==

(3)Signature簽名部分

簽名部分主要和token的安全性有關,Signature的生成依賴前面兩部分。
首先將Base64編碼後的Header和Payload用.鏈接在一塊兒,

ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9.ewogImlzcyI6ICJjaGJsb2dzLmNvbSIsCiAiZXhwIjogIjE0NzA3MzAxODIiLAogInVpZCI6ICIxMjM0NWFiY2RlIiwKfQ


對這個字符串使用HmacSHA256算法進行加密,這個密鑰secret存儲在服務端,前端不可見,

String str="ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9."
				+ "ewogImlzcyI6ICJjaGJsb2dzLmNvbSIsCiAiZXhwIjogIjE0NzA3MzAxODIiLAogInVpZCI6ICIxMjM0NWFiY2RlIiwKfQ";
    	byte[] inputData = str.getBytes();  
		String key = Coder.initMacKey();  
		BigInteger sha = new BigInteger(Coder.encryptHMAC(inputData, key));  
		System.out.println("HS256加密後——"+sha.toString(32));

  


下面使用密鑰 THISSHA 進行加密:
9q2eq8sa374ao2uq9607r6qu6

而後將Signature和前面兩部分拼接起來,獲得最後的token:

ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9.ewogImlzcyI6ICJjaGJsb2dzLmNvbSIsCiAiZXhwIjogIjE0NzA3MzAxODIiLAogInVpZCI6ICIxMjM0NWFiY2RlIiwKfQ.9q2eq8sa374ao2uq9607r6qu6

4、JWT認證的實現

常規的token保存在sessionStorage或者localStorage中,每次請求時將token加在http請求的Header中,

下面是典型的token認證方式:

1.客戶端登陸時經過帳號和密碼到服務端進行認證,認證經過後,服務端經過持有的密鑰生成Token,Token中通常包含失效時長和用戶惟一標識,如用戶ID,服務端返回Token給客戶端;
2.客戶端保存服務端返回的Token;
3.客戶端進行業務請求時在Head的Authorization字段裏面放置Token,如: 
Authorization: Bearer Token 
4.服務端對請求的Token進行校驗,若是Token不是存放在Cookie中,須要解決用戶主動註銷,但設置的過時時間並未過時問題。

用戶註銷時能夠把還在失效內的Token儲存在Redis等緩存中,驗證時查找Token是否存在,若是Token在Redis中存在,則說明用戶已註銷;若是Token不存在,則校驗經過。 
5.服務端能夠經過從Token取得的用戶惟一標識進行相關權限的校驗,並把此用戶標識賦予到請求參數中,業務可經過此用戶標識進行業務處理; 

還有一種方式是把token保存在Cookie中,這時就不須要在服務端保存token的值,用戶註銷時直接清除Cookie就能夠,

這種方式不須要在服務端儲存token的值,認證過程以下:


5、JWT標準的安全性

(1)如何訪問CSRF攻擊

CSRF (Cross Site Request Forgery),指在一個瀏覽器中打開了兩個標籤頁,其中一個頁面經過竊取另外一個頁面的 cookie 來發送僞造的請求,由於 cookie 是隨着請求自動發送到服務端的。

(2)如何保證token的安全性

客戶端不須要持有密鑰,由服務端經過密鑰生成Token;

在JWT中,不該該在Payload裏面加入任何敏感的數據,如用戶密碼等信息,由於payload並無作加密,只是一個Base64的編碼,
攻擊者拿到token之後就能夠獲得用戶敏感信息;

 

參考資料:

基於 Token 的身份驗證

JSON Web Token - 在Web應用間安全地傳遞信息

相關文章
相關標籤/搜索