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