本文是對 Token 技術(shù)的總結(jié)豹芯。
目錄
- 緣起
- 原理
- 優(yōu)勢
- 認證流程
- 注意事項
緣起
Token 的出現(xiàn)源于整個 Web 的發(fā)展歷史:
- Web 最初出現(xiàn)只是為了瀏覽文檔,從 HTTP 協(xié)議名稱(HyperText Transfer Protocol,超文本傳輸協(xié)議)中便可看出志群,HTTP 1.0 版本起初即被設計為無狀態(tài)。
- 隨著 Web 交互式應用的興起(如:在線購物),HTTP 協(xié)議無狀態(tài)性的局限很快被發(fā)現(xiàn)殉挽,為了管理會話并保留期間的狀態(tài)信息丰涉,很快想出了一個辦法,即服務端為每個客戶端生成一個會話標識(Session ID)斯碌,此會話標識(Session ID)是個隨機字符串一死,每個客戶端收到的不一樣,后續(xù)每個客戶端再發(fā)起請求時必須連同此會話標識(Session ID)一起發(fā)送傻唾,這樣服務端便可根據(jù)不同的會話標識(Session ID)區(qū)分請求來自于哪個客戶端投慈。
- 雖然通過會話標識(Session ID)已經(jīng)能夠區(qū)分不同的客戶端請求,但是隨著應用規(guī)模的增加冠骄,服務端面臨了幾個挑戰(zhàn):
- 因為服務端需要保存會話標識(Session ID)伪煤,因此一旦客戶端數(shù)量非常大時,服務端存儲開銷巨大凛辣;
- 當需要通過集群方案擴展服務端能力時抱既,會話標識(Session ID)的共享又成了一個問題,因為客戶端的請求可能會被轉(zhuǎn)發(fā)到不同的服務端節(jié)點扁誓,譬如第一次請求轉(zhuǎn)發(fā)到服務端節(jié)點 A防泵,下一次請求被轉(zhuǎn)發(fā)到服務器節(jié)點 B,那么 A 和 B 之間必須實現(xiàn)會話標識(Session ID)的共享跋理,否則客戶端在 A 已經(jīng)認證通過后,轉(zhuǎn)發(fā)到 B 后又要重新認證恬总。盡管可以通過不同的負載均衡算法保證一個客戶端的請求始終轉(zhuǎn)發(fā)到一個固定的服務節(jié)點前普,但一旦 IP 發(fā)生改變則很可能又要進行重新認證∫佳撸考慮到會話標識(Session ID)在多節(jié)點間復制的同步效率問題拭卿,通常會使用 Redis 等分布式系統(tǒng)集中緩存方案統(tǒng)一存放會話標識(Session ID),但這仍然依賴于 Redis 的可靠性贱纠,且存儲空間消耗的問題也未解決峻厚。
為了避免服務端存儲會話標識(Session ID),Token 應運而生谆焊。
原理
如果服務端不存儲會話標識(Session ID)惠桃,那么如何保證客戶端請求中帶的會話標識(Session ID)是有效的呢?如何避免偽造辖试?Token 的關(guān)鍵在于其不可偽造辜王。
Token 生成過程:
- 服務端認證通過客戶端身份后,利用部分有效數(shù)據(jù)組成一段明文罐孝,如:
{"username":"admin"}
呐馆; - 服務端使用一種加密算法加上一個只有自己才知道的密鑰對以上數(shù)據(jù)進行簽名,生成簽名字符串:
XXXXXX
莲兢; - 將明文和簽名字符串組合成一個文本:
{"username":"admin"}XXXXXX
汹来; - 對組合后的文本執(zhí)行
BASE64
編碼即得到 Token续膳; - 將此 Token 直接返回給客戶端,不在服務端保存收班;
- 客戶端再次發(fā)送回請求后坟岔,取出其中的 Token,首先執(zhí)行
BASE64
解碼闺阱,然后分離出明文段和簽名段炮车,使用第 2 步中相同的加密算法和密碼生成簽名字符串,與解碼后得到的簽名段進行比較即可判斷 Token 是否有效酣溃。
Token 實際上是一種 時間換空間 的方案瘦穆,即利用 CPU 加密的計算時間換取 會話標識(Session ID)的存儲空間。沒有了 會話標識(Session ID)的負擔赊豌,服務端的水平擴展便無需考慮集中存儲的瓶頸扛或,只需增減服務器數(shù)量即可。
優(yōu)勢
- 安全性
請求中發(fā)送 Token 而不再是發(fā)送 Cookie 能夠防止 CSRF(跨站請求偽造)碘饼,即使客戶端使用 Cookie 存儲 Token熙兔,此時的 Cookie 也只是用于存儲而非認證。
Token 具備時效性艾恼,也可以撤回住涉,通過 Revocation 可以使一個特定 Token 或一組有相同認證的 Token 失效。 - 無狀態(tài)
Token 是無狀態(tài)的钠绍,無需服務端存儲舆声。 - 可擴展
使用 Token 可以提供一定范圍的權(quán)限給第三方服務,可以開放獨立的 API 和特殊權(quán)限 Token 給第三方服務訪問柳爽。 - 多平臺跨域
通過將服務器屬性設置為Access-Control-Allow-Origin: *
可實現(xiàn)數(shù)據(jù)和資源能夠被任何域請求媳握。 - 基于標準
參考:JSON Web Tokens
認證流程
- 客戶端發(fā)送含有用戶名和密碼的身份認證請求;
- 服務端接收到請求后驗證用戶名和密碼磷脯;
- 驗證成功后服務端會生成一個 Token 并返回給客戶端蛾找;
- 客戶端將請求存儲在 Cookie、或 LocalStorage 中赵誓,客戶端在后續(xù)所有請求中都附帶上該 Token打毛;
- 服務端接收到請求后通過過濾器驗證 Token 有效性。
注意事項
- Token 中的明文數(shù)據(jù)不能存放敏感信息俩功。
- Token 應該放在 HTTP 的頭部隘冲,這樣才保證了 HTTP 請求的無狀態(tài)。
- 注意服務器屬性設置:
Access-Control-Allow-Origin: *
绑雄,讓服務器能夠接受來自所有域的請求展辞。