手寫jwt驗證,實現java和node無縫切換

前言

前端時間和我朋友寫了一個簡易用戶管理後臺,功能其實很簡單,涉及到的技術棧有:vue+elementUI,java+spring MVC以及node+egg,數據庫用的mysql,簡單方便。前端

一開始是我是隻負責前端,可是前端開發的的速度太快,總是沒事,加上他小子並無接觸過實戰的項目,又怕他出亂子,因此考慮我也寫一個後端,vue

開始考慮的是用python+django,可是仍是在半途放棄了,由於總感受Django不過靈活,使用起來很是彆扭,也多是用scrapy寫爬蟲寫多了,難以理解django的框架設計,老是會把他想象成一個scrapy架構,也致使代碼寫的很亂,下面上一張scrapy架構圖。java

因此最後考慮的用node,Express和Koa框架學習過node應該都知道,我之前也用過express(寫過一個小demo),可是給個人感受這到像是一個只能有5年以上node開發經驗才能玩的轉的,由於express是很是的精簡的,安裝它後,會發現它幾乎不會爲你提供任何編碼規範,也沒有約束你的框架應該怎麼設計,以致於新手下載完成後徹底不知道本身應該幹嗎,甚至不知道直接的文件應該寫在哪,沒有框架自己的約定,標準的MVC模型有着千奇百怪的寫法,因此我以爲沒有必定的架構思想和經驗是很難駕馭的。node

koa我並無直接的使用過,只是據說是express的原班人馬打造的,中間件是基於洋蔥圈模型實現的。下面上一張圖洋蔥圈模型圖。python

而是後來直接就接觸的egg,egg標語是「爲企業級框架和應用而生」,通道mysql

廢話說的有點多了,重點是通一套前端代碼,開發了兩套後端代碼,功能是徹底一致的,後端都實現了相應的jwt驗證功能,-->json web token,密鑰都是咱們約定好的固定值,可是最後發現同樣的密鑰,相同的數據,使用的jwt包不一樣產生的結果也不一樣,這也就致使兩端之間沒法相互切換,每次切換必須從登錄從新開始,這不太符合邏輯,並且重要的是後面的安排有須要這樣的功能,沒法作到無縫切換就直接致使實現不了下面的功能。web

提綱內容

  • jwt實現原理
  • jwt未能解決的疑惑
  • base64和base64url

jwt實現原理

其實做爲一個前端開發人員,jwt實現原理我是不必懂得的,可是若是你不限於此,這算是個必不可少的內容了吧。算法

先上一張圖。spring

圖中數字1是後端使用jwt工具包生成的token,一般是由三部分組成,也就是token中間的兩個「.」將其分爲三部分,第一部分對應的是右邊的數字2部分,而後依次對應。sql

這三部分分別是頭部、有效載荷、簽名。

頭部:alg是指說用到的算法,type固然是令牌類型

有效荷載:sub所簽發的用戶,name是簽發者的姓名,lat是這簽發時間,exp是指到期時間,固然還有一些其餘的,這些數據都是非必要數據,實則只有exp可能有用,由於有效數據實際都是在data裏面,固然你也能夠不這麼作。

簽名:前二者都是經過base64url編碼過的,而非是算法加密的,因此幾乎是透明的。可是簽名是默認是經過hsa256算法加密的 ,加密的規則是:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  your-256-bit-secret
)

如何驗證token呢?那更加簡單了,就是用前端傳回來的token前兩部分和服務器存的祕鑰再次加密一次,而後作base64url處理和第三部分比較,同樣表明這個token是本身簽發的,不同表明是僞造的,完了事後再將有效載荷部分進行base64url反編碼,就獲得exp,而後和當前時間比較是否過時。

jwt未能解決的疑惑

通過測試,發現三個問題。

一、 node和java使用對應的jwt工具包生成的token不相同,這裏是指在一系列參數徹底相同的狀況下。

二、 還發現用java生成的token在jwt官網解析時候輸入祕鑰結果的到的簽名和本身的簽名不同,可是node是同樣的,因而就產生了java工具包在輸入簽名的時候對密鑰進行了其餘處理的想法,可是他並無找出作出來怎麼樣的處理,也就是說咱們在生成簽名的時候根本就連密鑰都是不同的。

三、 不論是node仍是java生成的token,咱們用原來如出一轍的數據和同樣的算法公式都產生不了和工具包生成同樣的簽名,也就是能夠懷疑在進行hsa256算法加密前確實對祕鑰進行處理了。

base64和base64url

base64就是一種二進制編碼方式,原理很簡單,先準備一個包含64個字符的數組:

['A','B','C',...'a','b','c',...'0','1','2',...'+','/']

而後對二進制數據進行處理,每三個字節一組,一共24bit,一個字節8bit嘛,而後再將24分爲4組,每組正好6bit。6bit的話就恰好能表示64個字符。若是編碼字符不是3的倍數,就會剩下一個字節或者兩個字節,這個時候就在後面填充\x00,再在編碼末尾加上一個或者兩個=號。解碼的時候制動力去掉就行了。

base64url編碼就是將字符編碼成url能傳遞的參數,由於base64編碼會出現+號和/號,而後就會在url中出現問題,因此base64url其實就是將+和/分別變成-和_

相關文章
相關標籤/搜索