config/jwt.php
默認設置中,這個過時時間是一個小時,不過爲了安全也能夠設置更小一點,我設置了爲五分鐘。<?php namespace App\Http\Middleware; use App\Services\StatusServe; use Closure; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Exceptions\TokenExpiredException; use Tymon\JWTAuth\Http\Middleware\BaseMiddleware; class CheckUserLoginAndRefreshToken extends BaseMiddleware { /** * 檢查用戶登陸,用戶正常登陸,若是 token 過時 * 刷新 token 從響應頭返回 * * @param $request * @param Closure $next * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response * @throws JWTException */ public function handle($request, Closure $next) { /**************************************** * 檢查token 是否存在 ****************************************/ $this->checkForToken($request); try { /**************************************** * 嘗試經過 tokne 登陸,若是正常,就獲取到用戶 * 沒法正確的登陸,拋出 token 異常 ****************************************/ if ($this->auth->parseToken()->authenticate()) { return $next($request); } throw new UnauthorizedHttpException('jwt-auth', 'User not found'); } catch (TokenExpiredException $e) { try { /**************************************** * token 過時的異常,嘗試刷新 token * 使用 id 一次性登陸以保證這次請求的成功 ****************************************/ $token = $this->auth->refresh(); $id = $this->auth ->manager() ->getPayloadFactory() ->buildClaimsCollection() ->toPlainArray()['sub']; auth()->onceUsingId($id); } catch (JWTException $e) { /**************************************** * 若是捕獲到此異常,即表明 refresh 也過時了, * 用戶沒法刷新令牌,須要從新登陸。 ****************************************/ throw new UnauthorizedHttpException('jwt-auth', $e->getMessage(), null, StatusServe::HTTP_PAYMENT_REQUIRED); } } // 在響應頭中返回新的 token return $this->setAuthenticationHeader($next($request), $token); } }
<?php /* * This file is part of jwt-auth. * * (c) Sean Tymon <tymon148@gmail.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Tymon\JWTAuth\Http\Middleware; use Closure; use Exception; class Check extends BaseMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * * @return mixed */ public function handle($request, Closure $next) { if ($this->auth->parser()->setRequest($request)->hasToken()) { try { $this->auth->parseToken()->authenticate(); } catch (Exception $e) { } } return $next($request); } }
<?php namespace App\Http\Middleware; use Closure; use Exception; class Check extends BaseMiddleware { public function handle($request, Closure $next) { if ($this->auth->parser()->setRequest($request)->hasToken()) { try { $this->auth->parseToken()->authenticate(); } catch (TokenExpiredException $e) { // 此處作刷新 token 處理 // 具體代碼能夠參考必須須要登陸驗證的接口 // 在響應頭中返回新的 token return $this->setAuthenticationHeader($next($request), $token); } catch (Exception $e) { } } return $next($request); } }
問題解決。 最後說一個併發會出現的問題:php
# 當前 token_1 過時,先發起 a 請求,以後立刻發起 b 請求 # a 請求到服務器,服務器判斷過時,刷新 token_1 # 以後返回 token_2 給 a 請求響應 # 這時候遲一點的 b 請求用的仍是 token_1 # 服務器已經將此 token_1 加入黑名單,因此 b 請求無效 token_1 刷新返回 token_2 a 請求 --------> server -------> 成功 token_1 過時的 token_1,應該使用 token_2 b 請求 --------> server ------> 失敗
jwt-auth已經想到這種狀況,咱們只須要設置一個黑名單寬限時間便可 我設置爲5秒,就是當token_1過時了,你還能繼續使用token_1操做5秒時間前端
原文地址laravel