聊一聊數據接口的登陸態校驗以及JWT

最近和羣裏網友聊天,發現他在數據接口中校驗登陸狀態用的仍是session,在我及時勸說和科普以後,他最終決定改用JWT。那麼接下來咱們就聊一聊數據接口應該怎麼管理登陸狀態以及什麼是JWT前端

混合開發的時候是怎麼作的

先後端混合開發的時候,用戶登陸狀態的管理通常都是經過session來實現的,原理很簡單:用戶登陸後,服務端將登陸用戶信息存儲到服務器上的特定位置,並生成對應的session id存儲到瀏覽器的cookie中。須要校驗的時候先讀取cookie中的session id,找到服務器中對應的存儲內容,完成校驗。
很顯然,這個機制是創建在cookie基礎上的,cookie又依賴於瀏覽器,並且有域名限制。是不適合app、小程序、以及先後端時數據接口採用其餘域名等狀況的。算法

app、小程序、先後端分離的時候要怎麼作

app、小程序、先後端分離時的數據接口通常採用token來作登陸信息校驗。原理是用戶登陸後,服務端生成對應用戶的一個token(通常都是一段無心義的惟一字符串)後返回,app、小程序、前端(如下統稱爲前端)拿到token後保存,在須要校驗用戶登陸的接口請求中加入token(能夠是get、post參數或者http header的形式),服務端拿到token後校驗真實性、有效性等信息後完成登陸校驗。通常爲了防止盜用,還會設置一套簽名校驗的過程。
其實token和session的原理是差很少的,都是服務端將對應用戶的一個key(session的時候是session id,token的時候就是token)交給前端,前端經過token請求服務端,服務端再去反查用戶,獲取用戶登陸狀態。
如今通常微信、微博等接口都是採用的這種方式。可是這種方式也有弊端,主要是:json

  1. 服務端必須保存token,以及有效期,校驗的時候必需要有數據讀取的過程;
  2. 校驗簽名的時候通常須要一個secret作爲加密簽名的附加字符,前端必須也要同時保存這個secret,這樣顯然不適合代碼會暴露的網頁前端。

這時候,就輪到咱們此次的主角JWT出場了。小程序

什麼是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在實際使用中也是存在問題的,目前想到如下幾點:

  1. 安全性:簽名包含在token中,一旦token總體被盜用,將沒有辦法區分,因此有網友稱之爲「裸奔」;
  2. 過時時間放在token中而不是服務端保存處理,一旦token生成並簽發出去,將沒法靈活的控制有效期;
  3. 最後一個是用戶體驗,其實能夠算是token方式的通病。這個問題我也和羣友討論過,你們在訪問部分社區的時候應該會遇到過,還在訪問過程當中忽然變成未登陸。我以爲這主要時由於服務端在token過時後就即時判斷爲用戶登陸失敗,無論你在網頁上處於什麼狀態。這個問題在session方式中是不存在的,前面說過session依賴於cookie,而存儲session id的cookie是會保存在整個瀏覽器進程,就是說只要瀏覽器不關閉,用戶就能夠一直保持登陸狀態。
相關文章
相關標籤/搜索