电竞比分网-中国电竞赛事及体育赛事平台

分享

使用Json Web Token設(shè)計(jì)Passport系統(tǒng)

 WindySky 2017-09-17

一、Token Auth機(jī)制

基于Token的身份驗(yàn)證是無狀態(tài)的,我們不將用戶信息存在服務(wù)器或Session中。

相比原始的Cookie+Session方式,更適合分布式系統(tǒng)的用戶認(rèn)證,繞開了傳統(tǒng)的分布式Session一致性等問題。

基于Token的身份驗(yàn)證的主流程如下:

用戶通過用戶名和密碼發(fā)送請求;
程序驗(yàn)證;
程序返回一個(gè)簽名的token 給客戶端;
客戶端儲存token,并且每次用于每次發(fā)送請求。

二、相比Cookie認(rèn)證的優(yōu)勢

支持跨域跨站點(diǎn)訪問:

Cookie是不允許垮域訪問的,可以通過設(shè)置頂級域名的方式實(shí)現(xiàn)部分跨域,但是跨站點(diǎn)的訪問仍然不支持,
如果使用Token機(jī)制,就可以通過HTTP頭傳輸用戶認(rèn)證信息,從而更好的實(shí)現(xiàn)跨域跨站點(diǎn)。

無狀態(tài):

Token機(jī)制在服務(wù)端不需要存儲session信息,Token自身包含了登錄用戶的信息,只需要在客戶端的cookie或本地介質(zhì)存儲狀態(tài)信息;

去耦:不需要綁定到一個(gè)特定的身份驗(yàn)證方案。Token可以在任何地方生成,只要在你的API被調(diào)用的時(shí)候,你可以進(jìn)行Token生成調(diào)用即可;

更適用于移動(dòng)應(yīng)用:

當(dāng)客戶端是原生應(yīng)用時(shí),Cookie是不被支持的,雖然目前Webview的方式可以解決Cookie問題,

但是顯然采用Token認(rèn)證機(jī)制會簡單得多;

安全性更強(qiáng):

因?yàn)椴辉僖蕾囉贑ookie,所以你就不需要考慮對CSRF(跨站請求偽造)的防范;

標(biāo)準(zhǔn)化易擴(kuò)展:

可以采用標(biāo)準(zhǔn)化的 JSON Web Token (JWT),對以后系統(tǒng)接入Node等純前端開發(fā)更便捷;

相比Session一致性提高性能:

相比服務(wù)端保存Session一致性信息,并查詢用戶登錄狀態(tài),一般來說Token的驗(yàn)證過程(包含加密和解密),性能開銷會更小。

三、JSON Web Token標(biāo)準(zhǔn)的設(shè)計(jì)

JWT 標(biāo)準(zhǔn)的 Token 有三個(gè)部分:

header.payload.signature

三個(gè)部分中間用點(diǎn)分隔開,并且都使用 Base64 編碼,所以生成的 Token 類似這樣:

ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9.ewogImlzcyI6ICJjaGJsb2dzLmNvbSIsCiAiZXhwIjogIjE0NzA3MzAxODIiLAogInVpZCI6ICIxMjM0NWFiY2RlIiwKfQ.9q2eq8sa374ao2uq9607r6qu6

(1)Header報(bào)頭

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

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

Header內(nèi)容要用 Base64 的形式編碼,所以就變成這樣:
ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9

(2)Payload載荷部分

Payload 里面是 Token 的具體內(nèi)容,這部分內(nèi)容可以自定義,JWT有標(biāo)準(zhǔn)字段,也可以添加其它需要的內(nèi)容。
標(biāo)準(zhǔn)字段:
iss:Issuer,發(fā)行者
sub:Subject,主題
aud:Audience,觀眾
exp:Expiration time,過期時(shí)間
nbf:Not before
iat:Issued at,發(fā)行時(shí)間
jti:JWT ID

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

這部分內(nèi)容同樣要用Base64 編碼,生成編碼類似如下格式:

ewogImlzcyI6ICJjaGJsb2dzLmNvbSIsCiAiZXhwIjogIjE0NzA3MzAxODIiLAogInVpZCI6ICIxMjM0NWFiY2RlIiwKfQ==

(3)Signature簽名部分

簽名部分主要和token的安全性有關(guān),Signature的生成依賴前面兩部分。
首先將Base64編碼后的Header和Payload用.連接在一起,

ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9.ewogImlzcyI6ICJjaGJsb2dzLmNvbSIsCiAiZXhwIjogIjE0NzA3MzAxODIiLAogInVpZCI6ICIxMjM0NWFiY2RlIiwKfQ


對這個(gè)字符串使用HmacSHA256算法進(jìn)行加密,這個(gè)密鑰secret存儲在服務(wù)端,前端不可見,

1
2
3
4
5
6
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 進(jìn)行加密:
9q2eq8sa374ao2uq9607r6qu6

然后將Signature和前面兩部分拼接起來,得到最后的token:

ewogICJ0eXAiOiAiSldUIiwKICAiYWxnIjogIkhTMjU2Igp9.ewogImlzcyI6ICJjaGJsb2dzLmNvbSIsCiAiZXhwIjogIjE0NzA3MzAxODIiLAogInVpZCI6ICIxMjM0NWFiY2RlIiwKfQ.9q2eq8sa374ao2uq9607r6qu6

四、JWT認(rèn)證的實(shí)現(xiàn)

常規(guī)的token保存在sessionStorage或者localStorage中,每次請求時(shí)將token加在http請求的Header中,

下面是典型的token認(rèn)證方式:

1.客戶端登錄時(shí)通過賬號和密碼到服務(wù)端進(jìn)行認(rèn)證,認(rèn)證通過后,服務(wù)端通過持有的密鑰生成Token,Token中一般包含失效時(shí)長和用戶唯一標(biāo)識,如用戶ID,服務(wù)端返回Token給客戶端;
2.客戶端保存服務(wù)端返回的Token;
3.客戶端進(jìn)行業(yè)務(wù)請求時(shí)在Head的Authorization字段里面放置Token,如: 
Authorization: Bearer Token 
4.服務(wù)端對請求的Token進(jìn)行校驗(yàn),如果Token不是存放在Cookie中,需要解決用戶主動(dòng)注銷,但設(shè)置的過期時(shí)間并未過期問題。

用戶注銷時(shí)可以把還在失效內(nèi)的Token儲存在Redis等緩存中,驗(yàn)證時(shí)查找Token是否存在,如果Token在Redis中存在,則說明用戶已注銷;如果Token不存在,則校驗(yàn)通過。 
5.服務(wù)端可以通過從Token取得的用戶唯一標(biāo)識進(jìn)行相關(guān)權(quán)限的校驗(yàn),并把此用戶標(biāo)識賦予到請求參數(shù)中,業(yè)務(wù)可通過此用戶標(biāo)識進(jìn)行業(yè)務(wù)處理; 

還有一種方式是把token保存在Cookie中,這時(shí)就不需要在服務(wù)端保存token的值,用戶注銷時(shí)直接清除Cookie就可以,

這種方式不需要在服務(wù)端儲存token的值,認(rèn)證過程如下:


五、JWT標(biāo)準(zhǔn)的安全性

(1)如何訪問CSRF攻擊

CSRF (Cross Site Request Forgery),指在一個(gè)瀏覽器中打開了兩個(gè)標(biāo)簽頁,其中一個(gè)頁面通過竊取另一個(gè)頁面的 cookie 來發(fā)送偽造的請求,因?yàn)?cookie 是隨著請求自動(dòng)發(fā)送到服務(wù)端的。

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

客戶端不需要持有密鑰,由服務(wù)端通過密鑰生成Token;

在JWT中,不應(yīng)該在Payload里面加入任何敏感的數(shù)據(jù),如用戶密碼等信息,因?yàn)閜ayload并沒有做加密,只是一個(gè)Base64的編碼,
攻擊者拿到token以后就可以得到用戶敏感信息;

 

參考資料:

基于 Token 的身份驗(yàn)證

JSON Web Token - 在Web應(yīng)用間安全地傳遞信息

 

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多