why JWT
現(xiàn)在,前后端分離和 RESTful API 越來越火熱吹泡,當后臺漸漸開始只負責為客戶端提供 API 接口之后骤星,身份校驗和接口安全成了難題。在傳統(tǒng)的開發(fā)模式下爆哑,使用 cookie-session 可以保證接口安全洞难,在沒有登錄的情況下訪問關(guān)鍵數(shù)據(jù)會跳轉(zhuǎn)到登錄界面或者請求失敗。而使用 REStful API 之后揭朝,cookie-session 存在以下 3 個問題:
- 客戶端除了瀏覽器队贱,可能還包括手機端 APP色冀,對于手機端而言,管理 cookie 是一件麻煩的事情柱嫌。
- RESTful 風格的 API 不建議使用 cookie锋恬。
- cookie 本身有一個缺陷,不能跨域编丘。
正是存在上面的幾個缺陷与学,現(xiàn)在 API 開始使用 JWT 代替 cookie-session 來做身份驗證。
what JWT
JWT 全稱 JSON Web Token嘉抓。本質(zhì)上 JWT 是一串 token 字符串癣防。客戶端登錄之后掌眠,服務端返回一串 token 給客戶端孩等,之后每次客戶端請求 API 接口都需要攜帶該 token 進行身份校驗。JWT 由三個部分組成:頭部(header)痕鳍、載荷(payload)疲憋、簽名(signature)。這三個部分使用 .
連接在一起就是一個完整的 JWT渺尘。所以挫鸽,一個完整的 JWT 應該類似下面這種形式:
xxxxxx.yyyyy.zzzzz
header
header 是一個 json 數(shù)據(jù),用于描述 JWT 的基本信息鸥跟。一般要由兩個部分組成:
- alg
- typ
alg 代表的是加密所使用的算法(后面會提到加密數(shù)據(jù))丢郊,typ 表示該 token 是什么類型的。這里 typ 自然是 JWT医咨。
{
'alg':'HS256',
'typ':'JWT'
}
一個完整的 header 信息枫匾。最后使用 Base64 對 header 進行編碼,得到 JWT 的第一部分拟淮。
payload
payload 是 JWT 存儲信息的部分干茉。payload 也是一個 json 數(shù)據(jù),每一個 json 的 key-value 稱為一個聲明很泊。
payload 有兩種類型的聲明:標準聲明和自定義聲明角虫。
標準聲明一共有 6 個,其名稱和對應含義如下:
-
iss
: JWT 的簽發(fā)者委造。 -
iat
: JWT 的簽發(fā)時間戳鹅,是一個 unix 時間戳。 -
exp
: JWT 的過期時間昏兆,是一個 unxi 時間戳枫虏。 -
aud
: 接受 JWT 的一方。 -
sub
: JWT 所面向的用戶。 -
jti
: 唯一標識一個 JWT模软。
自定義聲明為用戶自己定義的 key-value伟骨,可以用來存儲一些簡單的基本信息∪家欤考慮到性能携狭,不應該在 payload 中定義太多自定義聲明。
定義一個 payload :
{
"iss": "jaychen",
"iat": 1441593502,
"exp": 1441594722,
"aud": "jaychen.cc",
"sub": "chenjiayaooo@gmail.com",
"jti:" "xxxxxxxx",
"user_id": "1",
"username": "jaychen"
}
上面這個 payload 中回俐,id
和 username
為自定義聲明逛腿。
有了 payload 只有,將該 payload 進行 Base64 加密仅颇,得到一串字符串之后单默,用 .
把 header 和 payload 連接起來。
signature
將 header 和 payload 兩個部分連接起來之后忘瓦,得到的字符串類似下面
xxxxx.yyyyy
接著搁廓,使用 header.alg
定義的加密算法對 hader.payload
的字符串進行加密,并且加密的時候應該有一個密鑰耕皮。加密之后境蜕,得到一串加密字符串,最后把這串加密字符串也是用 .
拼接在 header.payload
后面凌停,形成完整的 JWT粱年。
這里簽名的目的是為了保證 payload 數(shù)據(jù)的完整性。如果 JWT 在傳輸過程中被第三方劫持罚拟,中間人對 header.payload
進行修改台诗,并且使用自己的密鑰重新簽名。服務端收到中間人修改過的 JWT赐俗,使用自己的密鑰對 header.payload
進行再次加密拉队,由于中間人和服務端使用的是不同的密鑰簽名,所以服務端再次加密的結(jié)果肯定和中間人加密的結(jié)果不一致秃励,由此可以斷定該 JWT 被惡意篡改氏仗。
基于 JWT 的身份驗證
現(xiàn)在已經(jīng)明白了 JWT 的生成過程吉捶,現(xiàn)在來梳理下 JWT 的使用流程夺鲜。
- 首次登陸系統(tǒng),向服務端發(fā)送 username&&password 進行登錄呐舔。
- 服務端驗證 username&&password,驗證合法為客戶端生成一串 JWT币励,這里在 payload 中可以自定義聲明 user_id,username 等字段用來保存信息。
- 客戶端收到服務端的 JWT 字符串珊拼,自行保存食呻。后續(xù)需要請求 API 都要攜帶該 JWT 到服務端進行身份校驗。
- 服務端收到客戶端的 API 請求,先獲取 JWT 信息仅胞,通過簽名判斷 JWT 的合法性每辟,如果合法,返回數(shù)據(jù)干旧。
JWT 的優(yōu)點和注意事項
注意事項
上面生成 JWT 的過程中使用了 Base64 的加密算法對 payload 進行加密渠欺,Base64 是一種可逆的加密算法,這意味著其他人可以輕易的從加密結(jié)果中得到加密之前的信息椎眯,所以這注定了 payload 中不能保存密碼之類的敏感信息挠将。
優(yōu)點
回顧上面生成 JWT 的步驟,payload 中我們保存了 user_id
和 username
這樣的信息编整。在傳統(tǒng)的 cookie-session 中舔稀,這些數(shù)據(jù)是服務端在 session 中維護的。JWT 把之前需要在服務端維護的 session 數(shù)據(jù)轉(zhuǎn)移到客戶端掌测,使得服務端的壓力小了很多内贮。
JWT 本質(zhì)只是一串字符串,所以可以無限制的使用各種姿勢傳遞給服務端:當做 get 參數(shù)拼接在 URL 中汞斧、添加到 header 頭部中贺归、當做 post 參數(shù)傳遞。断箫。拂酣。
如果客戶端是手機 APP 等非瀏覽器客戶端,那么使用 JWT 就可以免去對 cookie 的管理仲义。
本文首發(fā)于:https://jaychen.cc
作者:jaychen