VerifyJWTToken.php 8.5 KB
<?php
/**
+-----------------------------------------------------------------------------------------------------------------------
 * 中间件:验证登录JWT token
+-----------------------------------------------------------------------------------------------------------------------
 *
 * @copyright   Copyright
 * @author      Richer
 * @package     App\Http\Middleware
 * @version     2019年10月9日,14:22:14
 * @link
 * @since       2019-10-09
 */
namespace App\Http\Middleware;

use App\Models\Admin\User as Admin;
use App\Models\User\User;
use Closure;
use JWTAuth;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;

class VerifyJWTToken extends BaseMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure                 $next
     * @return mixed
     */
    public 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 = $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);

        // 检测request中header头是否带了token
        //
        try {
            $this->checkForToken($request);
        } catch (UnauthorizedHttpException $e) {
            //Log::info('令牌没有提供');
            //获取到用户数据,并赋值给$user
            return response()->json([
                'code'  => 3001,
                'msg'   => __('please_log_in'), //token无效
                'data'  => null,//$e->getMessage(),
                'token' => '',
            ]);
        }

        // 提取token中用户数据
        try {
            // add by Richer 于 2021年6月16日11:19:49 获取用户的角色,根据角色来判断不同的用户表
            $role = $this->auth->parseToken()->getClaim('role');
            // 通过令牌验证用户。
            if ($role === 'admin') {
                $user =  \Auth::guard('api_admin')->authenticate();
            } else {
                $user = $this->auth->parseToken()->authenticate();
            }

            if (!$user) {
                //获取到用户数据,并赋值给$user
                return response()->json([
                    'code'  => 3002,
                    'msg'   => __('user_not_found_please_log_in'), //token无效
                    'data'  => null,
                    'token' => '',
                ]);
            }
//            // add by Richer 于 2021年6月16日11:19:49 获取用户的角色,根据角色来判断不同的用户表
//            $role = $this->auth->parseToken()->getClaim('role');
//            if ($role === 'admin') {
//                $user = Admin::find($user->id);
//            } else {
//                $user = User::find($user->id);
//            }

            // 如果获取用户信息正常,需要判断是否该用户是否存在,并且是否被禁用

            // 并且是否被禁用
            if ($user->status == config('constants.DISABLE')) {
                return response()->json([
                    'code'  => 3002,
                    'msg'   => __('user_be_disabled'),
                    'data'  => null,
                    'token' => '',
                ]);
            }

            // TODO 如果获取用户信息正常,需要判断是否是刷新了token ,控制只能在一个设备上进行登录
//            $token = $this->auth->parseToken()->getToken();
//            if ($user->token != $token) {
//                 return response()->json([
//                     'code'  => 3002,
//                     'msg'   => '该用户已在其他设备登录,请重新登录!',
//                     'data'  => null,
//                     'token' => '',
//                 ]);
//            }
            // add by Richer 于 2020年4月27日14:19:09 将用户信息也放在请求中,双保险
            $request->user  = $user;
//            dump($request->user);
            $request->role  = $role;
            $request->headers->set('role', $role); //
        } catch (TokenExpiredException $e) {
            // token 过期的情况
            try {
                //首先获得过期token 接着刷新token 再接着设置token并且验证token合法性
                $token = JWTAuth::refresh(JWTAuth::getToken());
                JWTAuth::setToken($token);
                $user = JWTAuth::authenticate($token);

                // Save user 刷新令牌,并将令牌重新入库
                if ($user) {
                    $user->token = $token;
                    $user->save();
                    // token被刷新之后,保证本次请求在controller中需要根据token调取登录用户信息能够执行成功
                    $request->user  = $user;
                    // 将token放在请求中,继续执行,最后将token返回到客户端,做到无痛刷新
                    $request->token = $token;

                    $request->headers->set('Authorization', 'Bearer '.$token); //
                }

                //Log::info(json_encode($request));
                // 继续
                return $next($request);

                //Log::info('令牌已过期,重新刷新,并继续执行');
                // 首先获得过期token 接着刷新token 再接着设置token并且验证token合法性
                // Refresh an expired token.
                $token = $this->auth->refresh($this->auth->getToken()->get());
                // Set the token
                $this->auth->setToken($token);
                // Authenticate a user via a token.
                $user  = $this->auth->authenticate($token);

                // Save user 刷新令牌,并将令牌重新入库
                $user->token = $token;
                $user->save();
                // token被刷新之后,保证本次请求在controller中需要根据token调取登录用户信息能够执行成功
                $request->user  = $user;
                // 将token放在请求中,继续执行,最后将token返回到客户端,做到无痛刷新
                $request->token = $token;

                $request->headers->set('Authorization', 'Bearer '.$token); //

                //Log::info(json_encode($request));
                // 继续
                return $next($request);
            } catch (JWTException $e) {
                //Log::info('该令牌已被列入黑名单');
                // 过期用户
                return response()->json([
                    'code'  => 3003,
                    'msg'   => __('login_info_expired_please_log_in_again'),//'该令牌已被列入黑名单,请重新登录!', // The token has been blacklisted
                    'data'  => null,//$e->getMessage(),
                    'token' => '',
                ]);
            }
        } catch (JWTException $e) {
            return response()->json([
                'code'  => 3001,
                'msg'   => __('login_info_expired_please_log_in_again'), //token已过期
                'data'  => null,//$e->getMessage(),
                'token' => '',
            ]);
        }

        // 令牌验证成功后,继续执行
        return $next($request);
    }
}