本文索引:
- 第一部分 基本概念
- 第二部分 使用流程
- 第三部分 實現代碼
第一部分 基本概念
JWT就是一個字符串,經過加密處理與校驗處理的字符串,由三個部分組成。基於token的身份驗證可以替代傳統的cookie+session身份驗證方法。三個部分分別如下:
<code> header.payload.signature/<code>
header部分:
<code>{"typ":"JWT","alg":"HS256"}/<code>
這就是一個json串,兩個字段都是必須的,alg字段指定了生成signature的算法,默認值為 HS256,可以自己指定其他的加密算法,如RSA.經過base64encode就可以得到 header.
payload部分:
<code>$payload=[ 'iss' => $issuer, //簽發者 'iat' => $_SERVER['REQUEST_TIME'], //什麼時候簽發的 'exp' => $_SERVER['REQUEST_TIME'] + 7200 //過期時間 'uid'=>1111 ];/<code>
signature部分
將 header和 payload使用header中指定的加密算法加密,當然加密過程還需要自定秘鑰,自己選一個字符串就可以了。
<code>HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)/<code>
php實現代碼:
<code> 'JWT', 'alg' => $alg])) . '.' . self::urlsafeB64Encode(json_encode($payload)); return $jwt . '.' . self::signature($jwt, $key, $alg); } public static function signature(string $input, string $key, string $alg) { return hash_hmac($alg, $input, $key); }/<code>
將以上三個部分連起來就是JWT了。
參數解釋
Screen-Shot-2018-09-06-at-3.24.30-PM.png
第二部分 JWT使用流程
實現步驟:
- 用戶登錄:輸入用戶名和密碼
- 服務器進行用戶名和密碼的校驗,通過之後生成JWT返回給前端
- 每次用戶請求API的時候都帶上JWT
- 服務端收到JWT做校驗
第三部分 實現代碼
首先composer安裝一個JWT庫,這裡使用的是firebase的庫,
<code>composer require firebase/php-jwt/<code>
服務端在生成token時,加入少量的用戶信息,比如用戶的id。服務端接收到token之後,可以解析出這些數據,從而將token和用戶關聯了起來。
使用很簡單,傳入秘鑰,生成Token:
<code>private function generateToken($key){ vendor('JWT.JWT'); $key = $user_key; $token = array( "iss" => "https://feifei50.com", // Issued At Claim "aud" => "https://feifei50.com", // Audience Claim "iat" => $_SERVER['REQUEST_TIME'], // Issued At Claim "nbf" => $_SERVER['REQUEST_TIME']-300, // Not Before Claim "exp" => $_SERVER["REQUEST_TIME"]+3600 // Expire Time Claim ); $jwt = JWT::encode($token, $key); return $jwt; }/<code>
返回的$jwt大概是這個樣子:
<code>//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvZmVpZmVpNTAuY29tIiwiYXVkIjoiaHR0cHM6XC9cL2ZlaWZlaTUwLmNvbSIsImlhdCI6MTUzNjI2OTM4NSwibmJmIjoxNTM2MjYxMDY1LCJleHAiOjE1MzYyNzk1NjV9.W19LwKH2eQbYs6YHKkbk7bOQK2dBfmV8jcNGIN4OGlY/<code>
key就是用來混淆的,自己隨便定義好了,encode 需要key,decode 也需要key,這裡用md5加密一下,會加入一個令牌混淆加密
在前端拿到這個token之後就將這個token放在LocalStroage中,每發送AJAX請求的時候都帶上這個token給服務端,服務端解碼這個token來做校驗,如果校驗沒有通過,那麼強制其跳回登錄頁面。
firebase的這個JWT會在解碼的時候做部分的校驗,比如key是否正確,token是否expired之類的,具體參考源碼,很容易理解。以後後端每次拿到這組Token就要從Token中進行解碼:
解碼Token
<code>private function decodeToken($jwt,$user_key){ JWT::$leeway = 300; // $leeway in seconds $decoded = JWT::decode($jwt, $user_key, array('HS256')); return $decoded;}/<code>
這樣解碼之後就拿到了之前定義的payload的信息即說需要的用戶信息。
本文作者熊冰,個人網站[Bing的天涯路],轉載請註明出處。
閱讀更多 熊冰 的文章