一、什么是JWT
JWT(JSON Web Token) 是一個開放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊的、自包含的方式,用于作為JSON對象在各方之間安全地傳輸信息。該信息可以被驗證和信任,因為它是數(shù)字簽名的。
二、使用場景(來自理解JWT的使用場景和優(yōu)劣)
- 一次性驗證:
比如用戶注冊后需要發(fā)一封郵件讓其激活賬戶,通常郵件中需要有一個鏈接,這個鏈接需要具備以下的特性:能夠標(biāo)識用戶,該鏈接具有時效性(通常只允許幾小時之內(nèi)激活),不能被篡改以激活其他可能的賬戶…這種場景就和 jwt 的特性非常貼近,jwt 的 payload 中固定的參數(shù):iss 簽發(fā)者和 exp 過期時間正是為其做準(zhǔn)備的。 - restful api的無狀態(tài)認(rèn)證
使用 jwt 來做 restful api 的身份認(rèn)證也是值得推崇的一種使用方案。客戶端和服務(wù)端共享 secret;過期時間由服務(wù)端校驗,客戶端定時刷新;簽名信息不可被修改。spring security oauth jwt 提供了一套完整的 jwt 認(rèn)證體系。
三、JWT結(jié)構(gòu)
JWT由三部分組成,它們之間用圓點(.)連接。這三部分分別是:
- Header
- Payload
- Signature
具體示例如下所示:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
3.1 Header
jwt的頭部由兩部分信息組成:
- type:聲明類型,這里是jwt
- alg:聲明加密的算法 通常直接使用 HMAC SHA256
完整的頭部信息如下:
{
"type":"jwt",
"alg":"HS256"
}
對頭部信息進(jìn)行Base64編碼的得到第一部分的信息
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
3.2 Payload
載荷就是存放有效信息的地方,它包含聲明(要求)。聲明有三種類型:
- registered claims:標(biāo)準(zhǔn)中注冊的聲明。這里有一組預(yù)定義的聲明,它們不是強(qiáng)制的,但是推薦
- public claims:公共的聲明
- private claims:私有的聲明
標(biāo)準(zhǔn)中注冊的聲明 (建議但不強(qiáng)制使用) :
- iss: jwt簽發(fā)者
- sub: jwt所面向的用戶
- aud: 接收jwt的一方
- exp: jwt的過期時間,這個過期時間必須要大于簽發(fā)時間
- nbf: 定義在什么時間之前,該jwt都是不可用的
- iat: jwt的簽發(fā)時間
- jti: jwt的唯一身份標(biāo)識,主要用來作為一次性token,從而回避重放攻擊
公共的聲明 :
公共的聲明可以添加任何的信息,一般添加用戶的相關(guān)信息或其他業(yè)務(wù)需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.
私有的聲明 :
私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息。
對Payload進(jìn)行Base64加密就得到了JWT第二部分的內(nèi)容。
3.3 signature
JWT的第三部分是一個簽證信息,這個簽證信息由三部分組成:
- header (base64后的)
- payload (base64后的)
- secret
第三部分需要base64加密后的header和base64加密后的payload使用 . 連接組成的字符串,然后通過header中聲明的加密方式進(jìn)行加鹽secret組合加密,然后就構(gòu)成了JWT的第三部分。
注意:
secret是保存在服務(wù)器端的,JWT的簽發(fā)生成也是在服務(wù)器端的,secret就是用來進(jìn)行JWT的簽發(fā)和JWT的驗證,所以,它就是你服務(wù)端的私鑰,在任何場景都不應(yīng)該流露出去。一旦客戶端得知這個secret, 那就意味著客戶端是可以自我簽發(fā)JWT了。
四、JWT,OAuth2,Session對比
4.1 傳統(tǒng)的session認(rèn)證
http協(xié)議本身是一種無狀態(tài)的協(xié)議,而這就意味著如果用戶向我們的應(yīng)用提供了用戶名和密碼來進(jìn)行用戶認(rèn)證,那么下一次請求時,用戶還要再一次進(jìn)行用戶認(rèn)證才行,因為根據(jù)http協(xié)議,我們并不能知道是哪個用戶發(fā)出的請求,所以為了讓我們的應(yīng)用能識別是哪個用戶發(fā)出的請求,我們只能在服務(wù)器存儲一份用戶登錄的信息,這份登錄信息會在響應(yīng)時傳遞給瀏覽器,告訴其保存為cookie,以便下次請求時發(fā)送給我們的應(yīng)用,這樣我們的應(yīng)用就能識別請求來自哪個用戶了,這就是傳統(tǒng)的基于session認(rèn)證。
但是這種基于session的認(rèn)證使應(yīng)用本身很難得到擴(kuò)展,隨著不同客戶端用戶的增加,獨立的服務(wù)器已無法承載更多的用戶,而這時候基于session認(rèn)證應(yīng)用的問題就會暴露出來:
- Session: 每個用戶經(jīng)過我們的應(yīng)用認(rèn)證之后,我們的應(yīng)用都要在服務(wù)端做一次記錄,以方便用戶下次請求的鑒別,通常而言session都是保存在內(nèi)存中,而隨著認(rèn)證用戶的增多,服務(wù)端的開銷會明顯增大
- 擴(kuò)展性: 用戶認(rèn)證之后,服務(wù)端做認(rèn)證記錄,如果認(rèn)證的記錄被保存在內(nèi)存中的話,這意味著用戶下次請求還必須要請求在這臺服務(wù)器上,這樣才能拿到授權(quán)的資源,這樣在分布式的應(yīng)用上,相應(yīng)的限制了負(fù)載均衡器的能力。這也意味著限制了應(yīng)用的擴(kuò)展能力
- CSRF: 因為是基于cookie來進(jìn)行用戶識別的, cookie如果被截獲,用戶就會很容易受到跨站請求偽造的攻擊
4.2 基于token的鑒權(quán)機(jī)制
JWT和OAuth2都是基于token的鑒權(quán)機(jī)制?;趖oken的鑒權(quán)機(jī)制類似于http協(xié)議也是無狀態(tài)的,它不需要在服務(wù)端去保留用戶的認(rèn)證信息或者會話信息。這就意味著基于token認(rèn)證機(jī)制的應(yīng)用不需要去考慮用戶在哪一臺服務(wù)器登錄了,這就為應(yīng)用的擴(kuò)展提供了便利。
其基本的流程如下:
- 用戶使用用戶名密碼來請求服務(wù)器
- 服務(wù)器進(jìn)行驗證用戶的信息
- 服務(wù)器通過驗證發(fā)送給用戶一個token
- 客戶端存儲token,并在每次請求時附送上這個token值
- 服務(wù)端驗證token值,并返回數(shù)據(jù)
這個token必須要在每次請求時傳遞給服務(wù)端,它應(yīng)該保存在請求頭里, 另外,服務(wù)端要支持CORS(跨來源資源共享)策略,一般我們在服務(wù)端這么做就可以了Access-Control-Allow-Origin: *。
4.3 JWT 認(rèn)證協(xié)議與 OAuth2.0 授權(quán)框架不恰當(dāng)比較(來自基于 Token 的 JWT 認(rèn)證協(xié)議與 OAuth2.0 授權(quán)框架不恰當(dāng)比較)
之所以說是不恰當(dāng),是因為JWT和OAuth2是完全不通過的概念。既然 JWT 和 OAuth2 沒有可比性,為什么還要把這兩個放在一起說呢?很多情況下,在討論OAuth2的實現(xiàn)時,會把JSON Web Token作為一種認(rèn)證機(jī)制使用。這也是為什么他們會經(jīng)常一起出現(xiàn)。
- JWT 是一種認(rèn)證協(xié)議
JWT提供了一種用于發(fā)布接入令牌(Access Token),并對發(fā)布的簽名接入令牌進(jìn)行驗證的方法。 令牌(Token)本身包含了一系列聲明,應(yīng)用程序可以根據(jù)這些聲明限制用戶對資源的訪問。 - OAuth2 是一種授權(quán)框架
OAuth2是一種授權(quán)框架,提供了一套詳細(xì)的授權(quán)機(jī)制。用戶或應(yīng)用可以通過公開的或私有的設(shè)置,授權(quán)第三方應(yīng)用訪問特定資源。 - JWT 使用場景
JWT 的主要優(yōu)勢在于使用無狀態(tài)、可擴(kuò)展的方式處理應(yīng)用中的用戶會話。服務(wù)端可以通過內(nèi)嵌的聲明信息,很容易地獲取用戶的會話信息,而不需要去訪問用戶或會話的數(shù)據(jù)庫。在一個分布式的面向服務(wù)的框架中,這一點非常有用。但是,如果系統(tǒng)中需要使用黑名單實現(xiàn)長期有效的 Token 刷新機(jī)制,這種無狀態(tài)的優(yōu)勢就不明顯了。
-
優(yōu)勢
- 快速開發(fā)
- 不需要 Cookie
- JSON 在移動端的廣泛應(yīng)用
- 不依賴于社交登錄
- 相對簡單的概念理解
-
限制
- Token有長度限制
- Token不能撤銷
- 需要 Token 有失效時間限制(exp)
- OAuth2 使用場景
如果不介意API的使用依賴于外部的第三方認(rèn)證提供者,你可以簡單地把認(rèn)證工作留給認(rèn)證服務(wù)商去做。也就是常見的,去認(rèn)證服務(wù)商(比如 Facebook)那里注冊你的應(yīng)用,然后設(shè)置需要訪問的用戶信息,比如電子郵箱、姓名等。當(dāng)用戶訪問站點的注冊頁面時,會看到連接到第三方提供商的入口。用戶點擊以后被重定向到對應(yīng)的認(rèn)證服務(wù)商網(wǎng)站,獲得用戶的授權(quán)后就可以訪問到需要的信息,然后重定向回來。
-
優(yōu)勢
- 快速開發(fā)
- 實施代碼量小
- 維護(hù)工作減少
- 可以和 JWT 同時使用
- 可針對不同應(yīng)用擴(kuò)展
-
限制
- 框架沉重