BearerToken之JWT的介紹(shao)
Bearer認證
HTTP提供了一套標準的身份(fen)驗(yan)證(zheng)框架(jia):服務器可(ke)(ke)以(yi)用來針對客(ke)戶端(duan)(duan)(duan)的請求(qiu)發(fa)送質(zhi)(zhi)詢(challenge),客(ke)戶端(duan)(duan)(duan)根據(ju)質(zhi)(zhi)詢提供身份(fen)驗(yan)證(zheng)憑證(zheng)。質(zhi)(zhi)詢與(yu)應答的工作流(liu)程如(ru)下:服務器端(duan)(duan)(duan)向客(ke)戶端(duan)(duan)(duan)返回401(Unauthorized,未授權)狀態(tai)碼,并(bing)在(zai)WWW-Authenticate頭中(zhong)添(tian)(tian)加如(ru)何(he)進行(xing)驗(yan)證(zheng)的信息(xi)(xi),其(qi)中(zhong)至少包(bao)含有一種質(zhi)(zhi)詢方式。然(ran)后客(ke)戶端(duan)(duan)(duan)可(ke)(ke)以(yi)在(zai)請求(qiu)中(zhong)添(tian)(tian)加Authorization頭進行(xing)驗(yan)證(zheng),其(qi)Value為身份(fen)驗(yan)證(zheng)的憑證(zheng)信息(xi)(xi)。
在HTTP標準(zhun)驗(yan)證(zheng)方案中,我們比較(jiao)熟悉的(de)是(shi)"Basic"和"Digest",前(qian)者(zhe)將(jiang)用戶名密碼使用BASE64編碼后作為驗(yan)證(zheng)憑(ping)證(zheng),后者(zhe)是(shi)Basic的(de)升級版,更加安全(quan),因為Basic是(shi)明(ming)文傳輸(shu)(shu)密碼信(xin)息,而Digest是(shi)加密后傳輸(shu)(shu)。在前(qian)文介紹的(de)Cookie認(ren)證(zheng)屬于(yu)(yu)Form認(ren)證(zheng),并不(bu)屬于(yu)(yu)HTTP標準(zhun)驗(yan)證(zheng)。
本文要介紹的Bearer驗(yan)證(zheng)也(ye)屬于HTTP協議(yi)標準(zhun)驗(yan)證(zheng),它隨著OAuth協議(yi)而開(kai)始流(liu)行,詳細定義見: 。
+--------+ +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+
Figure 1: Abstract Protocol Flow
Bearer驗證(zheng)中的(de)憑證(zheng)稱(cheng)為BEARER_TOKEN,或者(zhe)是access_token,它的(de)頒發(fa)和驗證(zheng)完(wan)全由我們(men)自己的(de)應用程序來控制,而不依賴于系統和Web服務器(qi),Bearer驗證(zheng)的(de)標(biao)準請求方式(shi)如下(xia):
Authorization: Bearer [BEARER_TOKEN]
JWT(JSON WEB TOKEN)
上(shang)面介紹(shao)的(de)Bearer認證,其核(he)心便是(shi)BEARER_TOKEN,而最流行的(de)Token編碼方式便是(shi):JSON WEB TOKEN。
Json web token (JWT), 是為了在網絡應用環境間傳遞聲明而執行的一種基于JSON的開放標準[RFC 7519()。該token被設計為緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便于從資源服務器獲取資源,也可以增加一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用于認證,也可被加密。
jwt主要包含以下三個內容:
- 頭部 Header
- 載荷 Payload
- 簽名 Signature
Jwt Token包含了使用.分隔的三部分
{Header 頭部}.{Payload 負載}.{Signature 簽名}
頭部 Header
Header 一(yi)般由兩個(ge)部分組成:
- alg
- typ
alg是(shi)是(shi)所使用的hash算法,如:HMAC SHA256或RSA,typ是(shi)Token的類(lei)型(xing),在這里就是(shi):JWT。
{
"alg": "HS256",
"typ": "JWT"
}
然后使(shi)用Base64Url編(bian)碼成第一部(bu)分
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.<second part>.<third part>
載荷 Payload
這(zhe)一部(bu)分是JWT主要(yao)的(de)信(xin)息存儲部(bu)分,其中包含(han)了(le)許多(duo)種的(de)聲明(ming)(claims)。
Claims的實體一(yi)般包含用戶和一(yi)些元數(shu)據,這(zhe)些claims分成三種(zhong)類型:
- reserved claims:預定義的 一些聲明,并不是強制的但是推薦,它們包括 iss (issuer), exp (expiration time), sub (subject),aud(audience) 等(這里都使用三個字母的原因是保證 JWT 的緊湊)。
- public claims: 公有聲明,這個部分可以隨便定義,但是要注意和 IANA JSON Web Token 沖突。
- private claims: 私有聲明,這個部分是共享被認定信息中自定義部分。
一個簡(jian)單的Pyload可(ke)以是這(zhe)樣子的:
{
"user_name": "admin",
"scope": [
"read","write","del"
],
"organization": "admin",
"exp": 1531975621,
"authorities": [
"ADMIN"
],
"jti": "23408d38-8cdc-4460-beac-24c76dc7629a",
"client_id": "webapp"
}
這部分同樣使用(yong)Base64Url編碼(ma)成第二部分
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.<third part>
簽名 Signature
Signature是(shi)用來(lai)驗證發送者(zhe)的(de)JWT的(de)同時也能(neng)確保在期(qi)間(jian)不被篡改。
簽名哈希部分是對上面兩部分數據簽名,通過指定的算法生成哈希,以確保數據不會被篡改。
首先(xian),需要(yao)指定一個密碼(ma)(secret)。該密碼(ma)僅僅為(wei)保存在服務器中,并且不能向用戶公開。然后,使用標頭中指定的(de)簽(qian)名算(suan)法(默認情況下為(wei)HMAC SHA256)根據以下公式生成簽(qian)名。
使(shi)用Base64編碼(ma)后的header和payload以(yi)及一(yi)個秘鑰,使(shi)用header中指定簽(qian)(qian)名算法進(jin)行簽(qian)(qian)名。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret)
結果
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
base64UrlEncode
如前所述,JWT頭和有效載荷序列化的算法都用到了Base64URL。該算法和常見Base64算法類似,稍有差別。
作(zuo)為(wei)令(ling)牌的JWT可以放在(zai)URL中(zhong)(例如api.example/?token=xxx)。 Base64中(zhong)用的三個字(zi)符是(shi)"+","/"和(he)"=",由于在(zai)URL中(zhong)有特(te)殊含義,因此Base64URL中(zhong)對他(ta)們做了替換:"="去掉,"+"用"-"替換,"/"用"_"替換,這(zhe)就是(shi)Base64URL算法,很簡(jian)單把。
JWT的工作過程
客戶端接收服務器返回的(de)JWT,將(jiang)其(qi)存儲在Cookie或localStorage中。
此(ci)后(hou),客戶端將(jiang)在與服務器(qi)交互中都會(hui)(hui)帶JWT。如果將(jiang)它存儲在Cookie中,就可以自(zi)動發(fa)送,但是(shi)不會(hui)(hui)跨域,因此(ci)一(yi)般是(shi)將(jiang)它放(fang)入HTTP請求的Header Authorization字段中。
Authorization: Bearer JWT_TOKEN
當(dang)跨域時,也可以(yi)將JWT被放置于POST請求的數據主體中。
使用JWT具有如下好處
- 通用:因為json的通用性,所以JWT是可以進行跨語言支持的,像JAVA,JavaScript,NodeJS,PHP等很多語言都可以使用。
- 緊湊:JWT的構成非常簡單,字節占用很小,可以通過 GET、POST 等放在 HTTP 的 header 中,非常便于傳輸。
- 擴展:JWT是自我包涵的,包含了必要的所有信息,不需要在服務端保存會話信息, 非常易于應用的擴展。