添加中間件,處理多個前端來的請求時,如果token需要刷新,先查看緩存,如果沒有就在redis中做個標志位進行短期緩存,其他的請求發現緩存中的token,就不再刷新token了。這樣就避免了重復刷新token的問題。
中間件代碼
<?php namespace App\Http\Middleware; use Closure; use JWTAuth; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Exceptions\TokenExpiredException; use Tymon\JWTAuth\Exceptions\TokenInvalidException; use Illuminate\Support\Facades\Redis; class GetUserFromToken { public function handle($request, Closure $next) { $newToken = null; $auth = JWTAuth::parseToken(); if (! $token = $auth->setRequest($request)->getToken()) { return response()->json([ 'code' => '2', 'msg' => '無參數token', 'data' => '', ]); } try { $user = $auth->authenticate($token); if (! $user) { return response()->json([ 'code' => '2', 'msg' => '未查詢到該用戶信息', 'data' => '', ]); } $request->headers->set('Authorization','Bearer '.$token); } catch (TokenExpiredException $e) { try { sleep(rand(1,5)/100); $newToken = JWTAuth::refresh($token); $request->headers->set('Authorization','Bearer '.$newToken); // 給當前的請求設置性的token,以備在本次請求中需要調用用戶信息 // 將舊token存儲在redis中,30秒內再次請求是有效的 Redis::setex('token_blacklist:'.$token,30,$newToken); } catch (JWTException $e) { // 在黑名單的有效期,放行 if($newToken = Redis::get('token_blacklist:'.$token)){ $request->headers->set('Authorization','Bearer '.$newToken); // 給當前的請求設置性的token,以備在本次請求中需要調用用戶信息 return $next($request); } // 過期用戶 return response()->json([ 'code' => '2', 'msg' => '賬號信息過期了,請重新登錄', ]); } } catch (JWTException $e) { return response()->json([ 'code' => '2', 'msg' => '無效token', 'data' => '', ]); } $response = $next($request); if ($newToken) { $response->headers->set('Authorization', 'Bearer '.$newToken); } return $response; } }