JWTRoleAuth.php 8.3 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\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 JWTRoleAuth 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'   => '请登录!', //token无效
                'data'  => null,//$e->getMessage(),
                'token' => '',
            ]);
        }

        // 提取token中用户数据
        try {
            // 通过令牌验证用户。
//            $user = $this->auth->parseToken()->authenticate();
            $user = $this->auth->parseToken()->getClaim('role');
            if (!$user) {
                //获取到用户数据,并赋值给$user
                return response()->json([
                    'code'  => 3002,
                    'msg'   => '未查询到该用户信息,请登录!', //token无效
                    'data'  => null,
                    'token' => '',
                ]);
            }

            // add by Richer 于 2021年6月16日11:19:49 获取用户的角色,根据角色来判断不同的用户表
            $role = optional($user)->role;
            dd($user);
            dump($role);
            // 如果获取用户信息正常,需要判断是否该用户是否存在,并且是否被禁用
            if (!$user = User::find($user->id)) {
                return response()->json([
                    'code'  => 3002,
                    'msg'   => '未查询到该用户信息,请登录!',
                    'data'  => '',
                    'token' => '',
                ]);
            }

            // 并且是否被禁用
            if ($user->status == User::DISABLE) {
                return response()->json([
                    'code'  => 3002,
                    'msg'   => '该用户已被禁用,请联系管理员!',
                    '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;
        } 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'   => '该令牌已被列入黑名单,请重新登录!', // The token has been blacklisted
                    'data'  => null,//$e->getMessage(),
                    'token' => '',
                ]);
            }
        } catch (JWTException $e) {
            return response()->json([
                'code'  => 3001,
                'msg'   => '登录信息已过期,请重新登录!', //token已过期
                'data'  => null,//$e->getMessage(),
                'token' => '',
            ]);
        }

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

        return $response;
    }
}