Laravel 中间件

一、概述

中间件为过滤进入应用程序的 HTTP 请求提供了一种方便的机制。

例如,Laravel 内置了一个中间件来验证用户的身份认证。如果用户没有通过身份认证,中间件会将用户重定向到登录界面。但是,如果用户被认证,中间件将允许该请求进一步进入该应用。

Laravel 自带了一些中间件,包括身份验证、CSRF 保护等。所有这些中间件都位于 app/Http/Middleware 目录。

二、中间件的使用

1、创建中间件

php artisan make:middleware CheckToken

该命令会在 app/Http/Middleware/ 目录下生成一个名为 CheckToken.php 的文件。

2、编写中间件代码
<?php

namespace App\Http\Middleware;

use App\Constants\Auth\Constants;
use App\Services\Auth\AuthBaseService;
use Closure;
use Firebase\JWT\JWT;
use Illuminate\Encryption\Encrypter;
use \Illuminate\Http\Request;
use \Exception;

class CheckToken extends AuthBaseService
{
    /**
     * Handle an incoming request.
     *
     * @param Request  $request
     * @param Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // $uri = $request->route()->uri(); // 获取请求的路由名称 getAnalysis,之后进行rbac权限校验
        $requestToken = $request->header('token');
        if (empty($requestToken)) return $this->response(Constants::TOKEN_FAIL, '未登录');
        try {
            /**
             * 解密请求token为jwt,如果解析不出,则抛出异常,由catch捕捉
             * @var Encrypter
             */
            $token = decrypt($requestToken, true);

            // 校验jwt-token,如果jwt-token不合法,这里会抛出异常,由catch接手处理
            $new = (array)JWT::decode($token, $this->getJwtSecret(), [$this->getAlg()]);
            if (empty($new)) {
                return $this->response(Constants::TOKEN_FAIL, 'token不合法');
            }

            // jwt-token二次校验
            if (!isset($new['userId']) || !isset($new['iss']) || $new['iss'] !== 'seeLove') {
                return $this->response(Constants::TOKEN_FAIL, 'token不合法');
            }
            $userId = $new['userId'];
            $expireTtl = $this->ttl($this->tokenPrefix.$userId);
            if ($expireTtl == -2 || !$expireTtl) return $this->response(Constants::TOKEN_FAIL,
                'token已过期,请重新登录');

            // 校验提交的token和缓存中的token是否一致(解决用户重新登录后,之前生成的token仍然有效[只允许一个用户持有一个token])
            if ($requestToken !== $this->getCache($this->tokenPrefix.$userId)) {
                return $this->response(Constants::TOKEN_FAIL, 'token已过期,请重新登录');
            }
            // 每次请求延长token45秒有效期
            $this->setCache($this->tokenPrefix.$userId, $requestToken, $expireTtl + 45);
        } catch (Exception $e) {
            return $this->response(Constants::TOKEN_FAIL, 'token不合法');
        }
        return $next($request);
    }

}

3、在app/Http/kernel.php引入该中间件

$routeMiddleware数组中添加元素

// 校验用户token
'checkToken' => CheckToken::class,