ThinkPHP 8 中间件管道深度实战:打造灵活可扩展的请求过滤与API安全体系

2026-06-05 0 288

在现代 Web 应用中,请求往往需要在到达控制器之前经过身份验证、数据过滤、日志记录等多个处理步骤。ThinkPHP 8 提供了强大的 中间件(Middleware) 机制,通过洋葱管道模型将这些处理步骤串联起来,使代码高度解耦且易于扩展。本文将从零讲解中间件的创建、注册和执行流程,并通过一个完整的 API 安全项目实战,让你彻底掌握中间件的所有核心用法。

一、中间件的本质:洋葱管道

ThinkPHP 的中间件采用“洋葱模型”执行:请求从外向内依次穿过所有前置中间件,进入控制器后再从内向外依次穿过中间件的后置处理。每个中间件都可以决定是继续传递请求还是直接返回响应。这种机制天然适合实现认证、授权、CORS、日志等横切关注点。

请求 → [中间件1前置] → [中间件2前置] → 控制器 → [中间件2后置] → [中间件1后置] → 响应

二、创建第一个自定义中间件

通过命令行快速生成中间件类:

php think make:middleware CheckAuth

该命令会在 app/middleware.php 同级目录或应用目录下创建中间件文件。手动创建同样简单,只需实现 handle 方法:

<?php
declare(strict_types=1);

namespace appmiddleware;

use thinkRequest;
use thinkResponse;

class CheckAuth
{
    /**
     * 处理请求
     * @param Request $request
     * @param Closure $next
     * @return Response
     */
    public function handle(Request $request, Closure $next): Response
    {
        // 前置检查:如果没有登录,则重定向到登录页
        if (!$request->session('user_id')) {
            return redirect('/login');
        }

        // 调用下一个中间件(或控制器)
        $response = $next($request);

        // 后置操作:可以在此记录日志或修改响应头
        $response->header('X-User-ID', $request->session('user_id'));

        return $response;
    }
}

这个中间件验证了用户会话,若未登录则终止传递并返回重定向响应,否则继续执行并在响应中添加自定义头。

三、中间件的注册方式

ThinkPHP 8 支持多种注册方式,灵活度极高。

3.1 全局中间件

app/middleware.php 中注册,作用于所有请求:

return [
    appmiddlewareCheckAuth::class,
    thinkmiddlewareSessionInit::class,
];

3.2 路由中间件

针对特定路由或路由组注册:

Route::group('api', function() {
    Route::get('users', 'api/User/index');
})->middleware(appmiddlewareApiAuth::class);

3.3 控制器中间件

在控制器中定义 $middleware 属性:

class UserController
{
    protected $middleware = [
        appmiddlewareLogAction::class => ['only' => ['update', 'delete']],
        appmiddlewareInjectUser::class => ['except' => ['index']],
    ];
}

该数组的键为中间件类名,值为限制条件(onlyexcept 指定操作方法)。

四、中间件参数传递

可以为中间件传入配置参数,增强复用性。例如创建一个 CheckRole 中间件,接受允许的角色列表:

<?php
namespace appmiddleware;

class CheckRole
{
    public function handle($request, Closure $next, string $role)
    {
        if (!in_array($request->user->role, explode(',', $role))) {
            return json(['error' => '权限不足'])->code(403);
        }
        return $next($request);
    }
}

注册时通过冒号传递参数:

Route::post('article', 'Article/create')
    ->middleware(CheckRole::class . ':admin,editor');

多个参数以逗号分隔,在 handle 方法中按顺序接收。

五、终止中间件:在响应发出后执行

有时需要在响应已经发送给客户端后执行某些操作(如记录长时间运行的任务、异步清理等)。可通过定义 end 方法实现终止中间件:

<?php
namespace appmiddleware;

class PerformanceMonitor
{
    private $startTime;

    public function handle($request, Closure $next)
    {
        $this->startTime = microtime(true);
        return $next($request);
    }

    // 在响应发送后调用
    public function end($response, $request)
    {
        $duration = microtime(true) - $this->startTime;
        $url = $request->url(true);
        // 记录慢请求到日志
        if ($duration > 2) {
            thinkfacadeLog::warning("慢请求: {$url} 耗时 {$duration}s");
        }
    }
}

注册该中间件后,每个请求的处理时间都会被监控,但不会影响响应速度。

六、实战案例:构建一个安全的 REST API

现在我们将创建一个实际的 API 模块,通过中间件实现签名验证、操作日志记录、跨域处理和请求限流。该模块为简单的文章管理接口,所有操作依赖 token 和签名。

6.1 API 路由定义

// route/app.php
use thinkfacadeRoute;

Route::group('api/v1', function () {
    Route::get('articles', 'api/Article/index');
    Route::get('articles/:id', 'api/Article/read');
    Route::post('articles', 'api/Article/create');
    Route::put('articles/:id', 'api/Article/update');
    Route::delete('articles/:id', 'api/Article/delete');
})->middleware([
    appmiddlewareCors::class,        // 跨域处理
    appmiddlewareApiThrottle::class, // 请求限流
    appmiddlewareApiAuth::class,     // 签名验证
    appmiddlewareOperationLog::class,// 操作日志
]);

6.2 跨域中间件 (Cors)

<?php
namespace appmiddleware;

class Cors
{
    public function handle($request, Closure $next)
    {
        // 如果是 OPTIONS 预检请求,直接返回 204 并附加头部
        if ($request->method() === 'OPTIONS') {
            $response = response('', 204);
        } else {
            $response = $next($request);
        }

        return $response->header([
            'Access-Control-Allow-Origin'  => '*',
            'Access-Control-Allow-Headers' => 'Content-Type, Token, Signature, Timestamp',
            'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
        ]);
    }
}

6.3 签名验证中间件 (ApiAuth)

<?php
namespace appmiddleware;

use thinkRequest;

class ApiAuth
{
    // 实际项目中存放于数据库或配置
    private $secretKey = 'abc123456';

    public function handle(Request $request, Closure $next)
    {
        $token = $request->header('Token');
        $signature = $request->header('Signature');
        $timestamp = $request->header('Timestamp');

        // 简单验证:签名 = md5(token + timestamp + secret)
        $expected = md5($token . $timestamp . $this->secretKey);

        if (!$token || !$signature || !$timestamp) {
            return json(['error' => '缺少必要参数'])->code(401);
        }

        // 防止重放攻击,5分钟内有效
        if (abs(time() - (int)$timestamp) > 300) {
            return json(['error' => '请求已过期'])->code(401);
        }

        if ($signature !== $expected) {
            return json(['error' => '签名验证失败'])->code(401);
        }

        // 将解析后的用户信息注入请求
        $request->userId = $this->resolveUserId($token);
        return $next($request);
    }

    private function resolveUserId($token)
    {
        // 实际解码 token 获取用户 ID
        return 1;
    }
}

6.4 操作日志中间件 (OperationLog)

<?php
namespace appmiddleware;

use thinkfacadeLog;

class OperationLog
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        $logData = [
            'user_id'  => $request->userId ?? 0,
            'url'      => $request->url(),
            'method'   => $request->method(),
            'ip'       => $request->ip(),
            'status'   => $response->getCode(),
        ];
        Log::info('API操作日志', $logData);
        return $response;
    }
}

6.5 请求限流中间件 (ApiThrottle)

<?php
namespace appmiddleware;

use thinkfacadeCache;

class ApiThrottle
{
    public function handle($request, Closure $next, int $maxRequests = 60, int $decayMinutes = 1)
    {
        $key = 'api_limit_' . ($request->userId ?? $request->ip());
        $current = (int) Cache::get($key, 0);
        if ($current >= $maxRequests) {
            return json(['error' => '请求过于频繁,请稍后再试'])->code(429);
        }

        Cache::set($key, $current + 1, $decayMinutes * 60);
        return $next($request);
    }
}

在路由注册限流中间件时,可以传入参数自定义限制:

->middleware(ApiThrottle::class . ':100,1')

6.6 控制器实现

文章控制器简略示例如下,所有安全与日志逻辑均已由中间件剥离:

<?php
namespace appcontrollerapi;

use thinkRequest;

class Article
{
    public function index()
    {
        $articles = appmodelArticle::select();
        return json($articles);
    }

    public function read($id)
    {
        $article = appmodelArticle::find($id);
        return $article ? json($article) : json(['error' => '文章不存在'])->code(404);
    }

    public function create(Request $request)
    {
        $data = $request->post();
        $article = appmodelArticle::create($data);
        return json($article)->code(201);
    }

    public function update(Request $request, $id)
    {
        $article = appmodelArticle::find($id);
        if (!$article) {
            return json(['error' => '文章不存在'])->code(404);
        }
        $article->save($request->post());
        return json($article);
    }

    public function delete($id)
    {
        $article = appmodelArticle::find($id);
        if ($article) $article->delete();
        return json(['message' => '删除成功']);
    }
}

七、中间件管道与执行顺序总结

以上案例中,一个请求经历的完整管道如下:

Cors 前置 → Throttle 前置 → Auth 前置 → Log 前置 → 控制器 → Log 后置 → Auth 后置 → Throttle 后置 → Cors 后置

这种结构让我们可以按需插入、移除或调整任意中间件,而无需改动业务代码。整个 API 的安全体系完全由中间件构成,实现了极致解耦。

八、结语

ThinkPHP 8 的中间件机制不仅是请求过滤工具,更是构建可扩展应用架构的基础。通过本文学到的创建、注册、参数传递及管道模型,你可以轻松将认证、授权、日志、限流等逻辑从控制器中解放出来,打造清晰、可维护的后端代码。在实际项目中,建议将通用功能抽象为中间件,让控制器专注于业务处理,从而让代码更符合 SOLID 原则。

现在,尝试在你的 ThinkPHP 8 项目中创建第一个中间件,体验请求管道的威力吧!

ThinkPHP 8 中间件管道深度实战:打造灵活可扩展的请求过滤与API安全体系
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请联系本站我们会及时删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 thinkphp ThinkPHP 8 中间件管道深度实战:打造灵活可扩展的请求过滤与API安全体系 https://www.taomawang.com/server/thinkphp/2086.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务