最近和羣裏網友聊天,發現他在數據接口中校驗登陸狀態用的仍是session,在我及時勸說和科普以後,他最終決定改用JWT。那麼接下來咱們就聊一聊數據接口應該怎麼管理登陸狀態以及什麼是JWT前端
先後端混合開發的時候,用戶登陸狀態的管理通常都是經過session來實現的,原理很簡單:用戶登陸後,服務端將登陸用戶信息存儲到服務器上的特定位置,並生成對應的session id存儲到瀏覽器的cookie中。須要校驗的時候先讀取cookie中的session id,找到服務器中對應的存儲內容,完成校驗。
很顯然,這個機制是創建在cookie基礎上的,cookie又依賴於瀏覽器,並且有域名限制。是不適合app、小程序、以及先後端時數據接口採用其餘域名等狀況的。算法
app、小程序、先後端分離時的數據接口通常採用token來作登陸信息校驗。原理是用戶登陸後,服務端生成對應用戶的一個token(通常都是一段無心義的惟一字符串)後返回,app、小程序、前端(如下統稱爲前端)拿到token後保存,在須要校驗用戶登陸的接口請求中加入token(能夠是get、post參數或者http header的形式),服務端拿到token後校驗真實性、有效性等信息後完成登陸校驗。通常爲了防止盜用,還會設置一套簽名校驗的過程。
其實token和session的原理是差很少的,都是服務端將對應用戶的一個key(session的時候是session id,token的時候就是token)交給前端,前端經過token請求服務端,服務端再去反查用戶,獲取用戶登陸狀態。
如今通常微信、微博等接口都是採用的這種方式。可是這種方式也有弊端,主要是:json
這時候,就輪到咱們此次的主角JWT出場了。小程序
JWT是JSON Web Token的簡稱,有官網詳細介紹,你們能夠看一看,這裏簡單說一下。
JWT其實就是一種特殊的token,原理和使用方法天然和token同樣。
JWT是由三部分組成的字符串,結構是:頭部+主體內容(官方稱之爲Payload)+簽名,三部分用「.」鏈接。頭部和主體內容都是json格式的字符串再通過base64編碼,爲了方便放在get請求中,還須要把相似「=」、「/」等特殊字符替換掉。後端
頭部內容是固定的,原始json就是下面這樣數組
{ "alg": "HS256", "typ": "JWT" }
主要是說明了最後簽名部分的加密算法。瀏覽器
重點是中間的主體內容,原始json通常是相似下面這樣的安全
{ "user": "John Doe", "exp": "2020-01-01 12:24:30" }
主體內容一個是當前登陸的用戶,能夠是用戶id,也能夠是用戶名等能夠檢索定位到用戶的信息;還有一個就是過時時間。還能夠加入一些其餘不私密的信息。
服務端拿到JWT以後能夠在不讀取數據的狀況下,僅經過解碼這部分信息就能夠完成獲取登陸用戶以及判斷是否過時等初期工做。服務器
最後的簽名通常是把頭部、主體內容再加上secret拼接成字符串再加密,這一步在用戶登陸生成JWT的時候就完成了。服務端拿到JWT以後只須要把前兩部分加上secret再計算一次簽名加以比對就能夠完成校驗簽名,前端不須要同時保存secret。微信
JWT官網提供了各類服務端語言的生成代碼,這裏我提供一個我本身用PHP寫的相對簡化的方法,供你們參考
private function _jwt($payload){ $header['alg']='HS256'; $header['typ']='JWT'; $jwt_header=$this->_base64url($header); $jwt_payload=$this->_base64url($payload); $jwt_sign=hash_hmac('sha256', $jwt_header.'.'.$jwt_payload, $this->secret); $jwt['token']=$jwt_header.'.'.$jwt_payload.'.'.$jwt_sign; $jwt['sign']=$jwt_sign; return $jwt; } private function _base64url($a){ $c=base64_encode(json_encode($a)); $c=str_replace('=', '', $c); $c=str_replace('+', '-', $c); $c=str_replace('/', '_', $c); return $c; }
我這個方法裏須要把主題內容以數組形式的參數傳入,最終返回了生成的JWT和簽名,方便接收時校驗簽名。
JWT在實際使用中也是存在問題的,目前想到如下幾點: