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