* * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace App\Http\Middleware; use App\Repositories\Enums\ResponseCodeEnum; use App\Support\Traits\LoginLimit; use Closure; use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Exceptions\TokenExpiredException; use Tymon\JWTAuth\Exceptions\TokenInvalidException; use Tymon\JWTAuth\Http\Middleware\BaseMiddleware; class Authenticate extends BaseMiddleware { use LoginLimit; /** * Handle an incoming request. * * @param Request $request * @param Closure $next * @param string|null $guard * @return mixed * * @throws AuthorizationException */ public function handle($request, Closure $next, $guard = null) { Auth::setDefaultDriver($guard); try { // 检查此次请求中是否带有 token,如果没有则抛出异常。 $this->checkForToken($request); } catch (TokenInvalidException $exception) { abort(ResponseCodeEnum::HTTP_UNAUTHORIZED, 'token有误'); } //1. 格式通过,验证是否是专属于这个的token //获取当前守护的名称 $guard = Auth::getDefaultDriver(); Log::error("1"); //使用 try 包裹,以捕捉 token 过期所抛出的 TokenExpiredException 异常 //2. 此时进入的都是属于当前guard守护的token try { // 检测用户的登录状态,如果正常则通过 if ($this->auth->parseToken()->authenticate()) { Log::error("2"); $token = Auth::getToken(); $user_id = $this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']; //单机登录检查 if (!$this->singleLoginCheck($token, $user_id, $guard)) { Log::error("3"); abort(ResponseCodeEnum::HTTP_UNAUTHORIZED, '该账号已经再其他设备上登录'); } Log::error("4"); return $next($request); } Log::error("5"); abort(ResponseCodeEnum::HTTP_UNAUTHORIZED, 'token过期,请重新登陆。'); } catch (TokenExpiredException $exception) { // 3. 此处捕获到了 token 过期所抛出的 TokenExpiredException 异常,我们在这里需要做的是刷新该用户的 token 并将它添加到响应头中 try { Log::error("6"); // 刷新用户的 token $token = $this->auth->refresh(); // 使用一次性登录以保证此次请求的成功 $user_id = $this->auth->manager()->getPayloadFactory()->buildClaimsCollection()->toPlainArray()['sub']; Auth::onceUsingId($user_id); $this->singleLoginSetToken($user_id, $token, $guard); Log::error("7"); return $this->setAuthenticationHeader($next($request), $token); } catch (JWTException $exception) { Log::error("8"); Log::error($exception); // 如果捕获到此异常,即代表 refresh 也过期了,用户无法刷新令牌,需要重新登录。 abort(ResponseCodeEnum::HTTP_UNAUTHORIZED, 'token令牌过期,请重新登陆。'); } } Log::error("9"); // 在响应头中返回新的 token abort(ResponseCodeEnum::HTTP_UNAUTHORIZED, '异常错误-Mead'); } }