個人github博客: https://zgxxx.github.io/
上一篇博客文章https://segmentfault.com/a/11... 介紹了laravel使用dingo+jwt開發API的幾個步驟,那麼在實際操做中,咱們須要測試APIphp
$api = app('Dingo\Api\Routing\Router'); $api->version('v1', ['namespace' => 'App\Http\Controllers\V1'], function ($api) { $api->post('register', 'AuthController@register'); $api->post('login', 'AuthController@login'); $api->post('logout', 'AuthController@logout'); $api->post('refresh', 'AuthController@refresh'); $api->post('me', 'AuthController@me'); $api->get('test', 'AuthController@test'); });
設置了這幾個路由,對應的url相似這樣:http://www.yourweb.com/api/me 使用postman來調試這些API。前端
咱們使用jwt代替session,首先是經過登陸(jwt的attempt方法驗證帳號密碼),成功後會返回一個JWT,咱們把這個字符串統一叫作token,這個token須要咱們客戶端保存起來,而後後面須要認證的接口就在請求頭裏帶上這個token,後臺驗證正確後就會進行下一操做,若是token錯誤,或者過時就返回401或500錯誤,拒絕後面的操做。laravel
前端能夠保存在localStorage,小程序能夠 使用wx.setStorageSync保存
因此請求頭信息Authorization:Bearer + token很重要,可是有個問題,這個token是有一個刷新時間和過時時間的:'ttl' => env('JWT_TTL', 60),
'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
git
token是會被別人盜取的,因此token須要每隔一段時間就更新一次
這時候有個問題,每隔一小時就更新,那豈不是要每小時就從新登陸一遍來獲取新token?固然不須要,咱們能夠寫個中間件來實現無痛刷新token,用戶不會察覺咱們已經更新了token。github
<?php namespace App\Http\Middleware; use Closure; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Http\Middleware\BaseMiddleware; use Tymon\JWTAuth\Exceptions\TokenExpiredException; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; class RefreshToken extends BaseMiddleware { /** * @author: zhaogx * @param $request * @param Closure $next * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response|mixed * @throws JWTException */ public function handle($request, Closure $next) { // 檢查這次請求中是否帶有 token,若是沒有則拋出異常。 $this->checkForToken($request); // 使用 try 包裹,以捕捉 token 過時所拋出的 TokenExpiredException 異常 try { // 檢測用戶的登陸狀態,若是正常則經過 if ($this->auth->parseToken()->authenticate()) { return $next($request); } throw new UnauthorizedHttpException('jwt-auth', '未登陸'); } catch (TokenExpiredException $exception) { // 此處捕獲到了 token 過時所拋出的 TokenExpiredException 異常,咱們在這裏須要作的是刷新該用戶的 token 並將它添加到響應頭中 try { // 刷新用戶的 token $token = $this->auth->refresh(); // 使用一次性登陸以保證這次請求的成功 \Auth::guard('api')->onceUsingId($this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']); } catch (JWTException $exception) { // 若是捕獲到此異常,即表明 refresh 也過時了,用戶沒法刷新令牌,須要從新登陸。 throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage()); } } return $next($request)->withHeaders([ 'Authorization'=> 'Bearer '.$token, ]); } }
一旦中間件檢測到token過期了,就自動刷新token,而後在響應頭把新的token返回來,咱們客戶端能夠根據響應頭是否有'Authorization'來決定是否要替換token
在使用postman調試這些API的時候就有個問題,postman又沒有前端代碼,我怎麼及時更新這個token,難道每次請求都要去看響應頭,發現Authorization後手動去複製黏貼嗎,固然也不須要,postman有個強大的環境變量,其實也是前端js的東西。web
首先點擊設置環境這個按鈕,點擊Add按鈕添加一個變量,咱們設置key值爲access_token,
json
接着咱們在登陸接口的Tests中去賦值這個變量
小程序
var data = JSON.parse(responseBody); if (data.result.access_token) { tests["Body has token"] = true; var tokenArray = data.result.access_token.split(" "); postman.setEnvironmentVariable("access_token", tokenArray[1]); } else { tests["Body has token"] = false; }
這段js代碼就是獲取請求成功後返回的access_token值,將其賦值給postman的環境變量,咱們看到請求成功後咱們後臺返回了一個json,其中就有咱們須要的access_token,咱們能夠再去環境變量那裏看看這時候的變量有什麼變化
segmentfault
能夠看到這裏的變量access_token已經有值了,就是咱們後臺返回來的access_token字符串,說明賦值成功api
接着咱們到另外一個須要認證的接口測試
咱們在Authorization類型type選擇Bearer Token,在後面Token表單那裏打一個'{'就會自動提示咱們設置過的變量{{access_token}}
發送請求測試下
已經成功了。
那若是token刷新了,通過後臺中間件無痛刷新後,會在響應頭返回一個新的token(這一次請求用的是舊的token,默認認證經過)
如今咱們須要在這個接口上直接更新咱們的變量access_token(以下圖),而不須要去再請求一遍登陸接口
var authHeader = postman.getResponseHeader('Authorization'); if (authHeader){ var tokenArray = authHeader.split(" "); postman.setEnvironmentVariable("access_token", tokenArray[1]); tests["Body has refreshtoken"] = true; } else { tests["Body has no refreshtoken"] = false; }
這段js代碼就是將響應頭中的Authorization賦值給咱們的access_token
這是響應頭的Authorization,截取了最後面的字符串
刷新時間過了後,咱們試着再發一次請求,咱們能夠看到,仍是能夠訪問的,並且請求頭裏的Authorization已經自動更新過來了
用一句話整理大概就是,你須要在哪一個接口響應後更新變量,就去這個這個口的Test下寫js賦值代碼postman.setEnvironmentVariable("access_token", token);
,只要沒錯誤你就能夠在別的地方使用{{access_token}}更新替換了。