* * 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\Contracts\Auth\Factory as Auth; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Exceptions\TokenExpiredException; class ApiAuthenticate { use LoginLimit; /** * The authentication guard factory instance. * * @var Auth */ protected $auth; /** * Create a new middleware instance. * * @param Auth $auth */ public function __construct(Auth $auth) { $this->auth = $auth; } /** * 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 = 'api') { try { if ($this->auth->guard($guard)->guest()) { abort(ResponseCodeEnum::HTTP_UNAUTHORIZED); } $token = \Illuminate\Support\Facades\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"); } 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令牌过期,请重新登陆。'); } } return $next($request); } /** * Set the authentication header. * * @param \Illuminate\Http\Response|\Illuminate\Http\JsonResponse $response * @param string|null $token * * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse */ protected function setAuthenticationHeader($response, $token = null) { $token = $token ?: $this->auth->refresh(); $response->headers->set('Authorization', 'Bearer ' . $token); return $response; } /** * Attempt to authenticate a user via the token in the request. * * @param \Illuminate\Http\Request $request * * @return void * @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException * */ public function authenticate(Request $request) { $this->checkForToken($request); try { if (!$this->auth->parseToken()->authenticate()) { throw new UnauthorizedHttpException('jwt-auth', 'User not found'); } } catch (JWTException $e) { throw new UnauthorizedHttpException('jwt-auth', $e->getMessage(), $e, $e->getCode()); } } /** * Check the request for the presence of a token. * * @param \Illuminate\Http\Request $request * * @return void * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException * */ public function checkForToken(Request $request) { if (!$this->auth->parser()->setRequest($request)->hasToken()) { throw new UnauthorizedHttpException('jwt-auth', 'Token not provided'); } } } // ///* // * This file is part of the Jiannei/lumen-api-starter. // * // * (c) Jiannei // * // * 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 ApiAuthenticate 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 = 'api') // { // Auth::setDefaultDriver('api'); // // 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()) { // if ($this->auth->guest()) { // 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'); //// return $this->setAuthenticationHeader($next($request), $token); // } //}