天天看點

使用Json Web Token設計Passport系統

<b>一、</b>token auth機制

基于token的身份驗證是無狀态的,我們不将使用者資訊存在伺服器或session中。

相比原始的cookie+session方式,更适合分布式系統的使用者認證,繞開了傳統的分布式session一緻性等問題。

基于token的身份驗證的主流程如下:

使用者通過使用者名和密碼發送請求; 程式驗證; 程式傳回一個簽名的token 給用戶端; 用戶端儲存token,并且每次用于每次發送請求。

支援跨域跨站點通路:

cookie是不允許垮域通路的,可以通過設定頂級域名的方式實作部分跨域,但是跨站點的通路仍然不支援,

如果使用token機制,就可以通過http頭傳輸使用者認證資訊,進而更好的實作跨域跨站點。

無狀态:

token機制在服務端不需要存儲session資訊,token自身包含了登入使用者的資訊,隻需要在用戶端的cookie或本地媒體存儲狀态資訊;

去耦:不需要綁定到一個特定的身份驗證方案。token可以在任何地方生成,隻要在你的api被調用的時候,你可以進行token生成調用即可;

更适用于移動應用:

當用戶端是原生應用時,cookie是不被支援的,雖然目前webview的方式可以解決cookie問題,

但是顯然采用token認證機制會簡單得多;

安全性更強:

因為不再依賴于cookie,是以你就不需要考慮對csrf(跨站請求僞造)的防範;

标準化易擴充:

可以采用标準化的 json web token (jwt),對以後系統接入node等純前端開發更便捷;

相比session一緻性提高性能:

相比服務端儲存session一緻性資訊,并查詢使用者登入狀态,一般來說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存儲在服務端,前端不可見,

  

下面使用密鑰 thissha 進行加密:

9q2eq8sa374ao2uq9607r6qu6

然後将signature和前面兩部分拼接起來,得到最後的token:

正常的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取得的使用者唯一辨別進行相關權限的校驗,并把此使用者辨別賦予到請求參數中,業務可通過此使用者辨別進行業務處理; 

使用Json Web Token設計Passport系統

還有一種方式是把token儲存在cookie中,這時就不需要在服務端儲存token的值,使用者登出時直接清除cookie就可以,

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

使用Json Web Token設計Passport系統

csrf (cross site request forgery),指在一個浏覽器中打開了兩個标簽頁,其中一個頁面通過竊取另一個頁面的 cookie 來發送僞造的請求,因為 cookie 是随着請求自動發送到服務端的。

用戶端不需要持有密鑰,由服務端通過密鑰生成token;

在jwt中,不應該在payload裡面加入任何敏感的資料,如使用者密碼等資訊,因為payload并沒有做加密,隻是一個base64的編碼,

攻擊者拿到token以後就可以得到使用者敏感資訊;

參考資料:

<a href="http://ninghao.net/blog/2834" target="_blank">基于 token 的身份驗證</a>

<a href="https://leon_lizi.gitbooks.io/json-web-token/content/chapter1.html" target="_blank">json web token - 在web應用間安全地傳遞資訊</a>

繼續閱讀