為保證和前端交互過程中,用戶可以自動刷新token
1.創建一個中間件文件,命名為 RefreshToken
<?php namespace App\Http\Middleware; use Auth; use Closure; use Tymon\JWTAuth\JWTAuth; 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 { 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的 * 當JWT_BLACKLIST_ENABLED=false時,可以在JWT_REFRESH_TTL時間內,無限次刷新使用舊的token換取新的token * 當JWT_BLACKLIST_ENABLED=true時,刷新token后舊的token即刻失效,被放入黑名單 * */ // 刷新用戶的 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()); } } // 在響應頭中返回新的 token return $this->setAuthenticationHeader($next($request), $token); } }
2.修改App\Http\Kernel.pho文件
protected $routeMiddleware = [ //...... 'token.refresh' => \App\Http\Middleware\RefreshToken::class, //...... ];
3.修改routes.api.php文件
// 需要 token 驗證的接口 $api->group(['middleware' => ['token.refresh','auth.jwt']], function($api) { //....... });
4.修改.env文件
#Jwt JWT_SECRET=HSKxIUfwCdJj5gadbqfQo5im9zje95g9 #token有效時間,單位:分鍾, 有效時間調整為2個小時 JWT_TTL=120 #為了使令牌無效,您必須啟用黑名單。如果不想或不需要此功能,請將其設置為 false。 #當JWT_BLACKLIST_ENABLED=false時,可以在JWT_REFRESH_TTL時間內,無限次刷新使用舊的token換取新的token #當JWT_BLACKLIST_ENABLED=true時,刷新token后舊的token即刻失效,被放入黑名單 JWT_BLACKLIST_ENABLED=true #當多個並發請求使用相同的JWT進行時,由於 access_token 的刷新 ,其中一些可能會失敗,以秒為單位設置請求時間以防止並發的請求失敗。 #時間為10分鍾,10分鍾之內可以拿舊的token換取新的token。當JWT_BLACKLIST_ENABLED為true時,可以保證不會立即讓token失效 JWT_BLACKLIST_GRACE_PERIOD=600
5.備注:
JWT token的三個時間,config/jwt.php查看
a.有效時間,有效是指你獲取token后,在多少時間內可以憑這個token去獲取資源,逾期無效。
'ttl' => env('JWT_TTL', 60), //單位分鍾
b.刷新時間,刷新時間指的是在這個時間內可以憑舊 token 換取一個新 token。例如 token 有效時間為 60 分鍾,刷新時間為 20160 分鍾,在 60 分鍾內可以通過這個 token 獲取新 token,但是超過 60 分鍾是不可以的,然后你可以一直循環獲取,直到總時間超過 20160 分鍾,不能再獲取。
這里要強調的是,是否在刷新期可以一直用舊的token獲取新的token,這個是由blacklist_enabled這個配置決定的,這個是指是否開啟黑名單,默認是開啟的,即刷新后,舊token立馬加入黑名單,不可在用。
'refresh_ttl' => env('JWT_REFRESH_TTL', 20160),
c.寬限時間,寬限時間是為了解決並發請求的問題,假如寬限時間為 0s ,那么在新舊 token 交接的時候,並發請求就會出錯,所以需要設定一個寬限時間,在寬限時間內,舊 token 仍然能夠正常使用
// 寬限時間需要開啟黑名單(默認是開啟的),黑名單保證過期token不可再用 'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true) // 設定寬限時間,單位:秒 'blacklist_grace_period' => env('JWT_BLACKLIST_GRACE_PERIOD', 600)