Laravel Middleware Chi Tiết: Xác Thực, Rate Limiting và Custom Middleware

Hướng dẫn toàn diện về Laravel middleware với các ví dụ thực tế về authentication guard, rate limiting với throttle, tạo custom middleware, PHP attribute trong Laravel 13, và các pattern nâng cao cho ứng dụng production.

Kien truc Laravel Middleware voi request pipeline, xac thuc va rate limiting

Middleware trong Laravel đóng vai trò như một lớp lọc giữa các HTTP request đến và logic xử lý của ứng dụng. Mỗi request đều phải đi qua một chuỗi các lớp middleware trước khi tới được controller, và mỗi response cũng đi ngược lại qua chính chuỗi đó. Việc nắm vững cơ chế này là điều thiết yếu để xây dựng các ứng dụng Laravel an toàn và có hiệu suất cao.

Middleware trong một câu

Middleware chặn các HTTP request trước khi chúng tới được route. Laravel đăng ký toàn bộ middleware trong bootstrap/app.php thông qua fluent API. Các middleware tích hợp sẵn xử lý authentication, bảo vệ CSRF, quản lý session và rate limiting ngay khi cài đặt.

Cơ Chế Hoạt Động Của Middleware Pipeline Trong Laravel

HTTP kernel của Laravel xử lý mỗi request thông qua một stack middleware. Mỗi middleware nhận request, thực hiện logic của mình, rồi chuyển request sang lớp tiếp theo thông qua $next($request) hoặc cắt ngang pipeline bằng cách trả về response trực tiếp.

Kiến trúc này tuân theo pattern Chain of Responsibility. Middleware có thể hoạt động trước khi request đến controller (ví dụ: kiểm tra authentication), sau khi response được tạo (ví dụ: thêm header), hoặc cả hai.

app/Http/Middleware/LogRequestTime.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;

class LogRequestTime
{
    public function handle(Request $request, Closure $next): Response
    {
        $start = microtime(true);          // Capture start time

        $response = $next($request);       // Pass to next middleware

        $duration = microtime(true) - $start;
        Log::info('Request completed', [
            'url'      => $request->url(),
            'method'   => $request->method(),
            'duration' => round($duration * 1000, 2) . 'ms',
        ]);

        return $response;                  // Return response up the stack
    }
}

Middleware trên bao bọc request: ghi lại thời gian bắt đầu trước khi xử lý và ghi lại thời lượng sau khi response được trả về. Pattern before/after này là cốt lõi của cách middleware hoạt động.

Authentication Middleware: Bảo Vệ Route

Laravel cung cấp sẵn middleware alias auth, được ánh xạ tới Illuminate\Auth\Middleware\Authenticate. Khi áp dụng middleware này cho một route, chỉ những người dùng đã xác thực mới có thể truy cập. Người dùng chưa xác thực sẽ nhận response 401 (đối với API) hoặc được chuyển hướng tới trang đăng nhập (đối với web).

routes/web.phpphp
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\ProfileController;

// Single route protection
Route::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware('auth');

// Group protection for multiple routes
Route::middleware('auth')->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
    Route::put('/profile', [ProfileController::class, 'update']);
    Route::delete('/profile', [ProfileController::class, 'destroy']);
});

Xác Thực Đa Guard

Các ứng dụng có nhiều loại người dùng (panel quản trị, khu vực khách hàng, API) cần sử dụng xác thực dựa trên guard. Middleware auth chấp nhận tham số guard để chỉ định driver xác thực nào sẽ được sử dụng.

routes/api.phpphp
// API routes use the 'sanctum' guard
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', fn (Request $request) => $request->user());
    Route::apiResource('/orders', OrderController::class);
});

// routes/web.php
// Admin routes use a custom 'admin' guard
Route::middleware('auth:admin')->prefix('admin')->group(function () {
    Route::get('/dashboard', [AdminController::class, 'index']);
    Route::get('/users', [AdminController::class, 'users']);
});

Tham số guard sau dấu hai chấm cho Laravel biết cấu hình xác thực nào cần kiểm tra. Cách tiếp cận này giữ logic xác thực gọn gàng và tách biệt giữa các phần khác nhau của ứng dụng.

Guest Middleware

Middleware guest là nghịch đảo của auth, chỉ cho phép người dùng chưa xác thực đi qua. Áp dụng middleware này cho các route đăng nhập và đăng ký giúp ngăn người dùng đã xác thực truy cập lại những trang đó.

Rate Limiting Với Throttle Middleware

Rate limiting trên middleware Laravel bảo vệ các route khỏi sự lạm dụng bằng middleware throttle tích hợp sẵn. Dạng đơn giản nhất chấp nhận hai tham số: số lượng request tối đa và khung thời gian tính bằng phút.

routes/api.phpphp
// Allow 60 requests per minute per user
Route::middleware('throttle:60,1')->group(function () {
    Route::get('/posts', [PostController::class, 'index']);
    Route::get('/posts/{post}', [PostController::class, 'show']);
});

// Stricter limit for write operations
Route::middleware(['auth:sanctum', 'throttle:10,1'])->group(function () {
    Route::post('/posts', [PostController::class, 'store']);
    Route::put('/posts/{post}', [PostController::class, 'update']);
});

Named Rate Limiters Cho Kiểm Soát Nâng Cao

Việc định nghĩa named rate limiters trong AppServiceProvider mang lại khả năng kiểm soát chi tiết dựa trên ngữ cảnh người dùng. Cách tiếp cận này linh hoạt hơn nhiều so với việc truyền tham số throttle trực tiếp. Xem tài liệu rate limiting chính thức để biết thêm các tùy chọn.

app/Providers/AppServiceProvider.phpphp
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Http\Request;

public function boot(): void
{
    // API rate limiter with tiered access
    RateLimiter::for('api', function (Request $request) {
        $user = $request->user();

        if ($user?->hasSubscription('enterprise')) {
            return Limit::perMinute(500)->by($user->id);   // Enterprise: 500/min
        }

        if ($user) {
            return Limit::perMinute(100)->by($user->id);   // Authenticated: 100/min
        }

        return Limit::perMinute(20)->by($request->ip());   // Anonymous: 20/min
    });

    // Login limiter to prevent brute force
    RateLimiter::for('login', function (Request $request) {
        return Limit::perMinute(5)
            ->by($request->ip())                            // Key by IP address
            ->response(function () {                        // Custom exceeded response
                return response()->json([
                    'message' => 'Too many login attempts. Try again in a minute.',
                ], 429);
            });
    });
}

Các named limiter được áp dụng cho route thông qua cú pháp throttle:name:

routes/api.phpphp
Route::middleware('throttle:api')->group(function () {
    Route::apiResource('/posts', PostController::class);
});

// routes/web.php
Route::middleware('throttle:login')
    ->post('/login', [AuthController::class, 'login']);

Tiered rate limiter ở trên thể hiện một pattern production: người dùng enterprise nhận limit cao hơn, người dùng đã xác thực nhận limit vừa phải, và các request ẩn danh bị hạn chế nghiêm ngặt. Phương thức by() xác định rate limit key, sử dụng user ID cho người dùng đã xác thực và địa chỉ IP làm phương án dự phòng.

Sẵn sàng chinh phục phỏng vấn Laravel?

Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.

Xây Dựng Custom Middleware Từ Đầu

Việc tạo custom middleware bao gồm các tình huống mà middleware tích hợp sẵn không xử lý được. Lệnh Artisan make:middleware tạo ra một class mới với cấu trúc đúng.

bash
php artisan make:middleware EnsureUserHasRole

Middleware Kiểm Soát Truy Cập Theo Vai Trò

Một pattern phổ biến cho custom middleware là kiểm soát quyền truy cập dựa trên vai trò (role-based authorization) ở cấp route, với việc nhận tên role làm tham số.

app/Http/Middleware/EnsureUserHasRole.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureUserHasRole
{
    public function handle(Request $request, Closure $next, string ...$roles): Response
    {
        $user = $request->user();

        if (! $user || ! $user->hasAnyRole($roles)) {
            abort(403, 'Insufficient permissions.');
        }

        return $next($request);
    }
}

Tham số variadic ...$roles cho phép truyền nhiều role cách nhau bằng dấu phẩy. Việc đăng ký và sử dụng như sau:

bootstrap/app.phpphp
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'role' => App\Http\Middleware\EnsureUserHasRole::class,
    ]);
})

// routes/web.php
Route::middleware('role:admin')->group(function () {
    Route::get('/admin', [AdminController::class, 'index']);
});

// Multiple roles: admin OR editor can access
Route::middleware('role:admin,editor')->group(function () {
    Route::resource('/articles', ArticleController::class);
});

Middleware Biến Đổi Request

Middleware có thể sửa đổi request trước khi nó tới controller. Một middleware cho JSON API kiểm tra content type header và làm sạch các chuỗi đầu vào bằng cách loại bỏ khoảng trắng thừa:

app/Http/Middleware/ApiRequestSanitizer.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class ApiRequestSanitizer
{
    public function handle(Request $request, Closure $next): Response
    {
        // Reject non-JSON requests on API routes
        if (! $request->expectsJson() && $request->isMethod('POST')) {
            return response()->json(
                ['error' => 'Content-Type must be application/json'],
                415
            );
        }

        // Trim all string inputs
        $input = $request->all();
        array_walk_recursive($input, function (&$value) {
            if (is_string($value)) {
                $value = trim($value);
            }
        });
        $request->merge($input);

        return $next($request);
    }
}

Middleware này xử lý hai vấn đề cùng lúc: kiểm tra content type cho các POST request và làm sạch tất cả đầu vào dạng chuỗi bằng cách trim khoảng trắng.

Đăng Ký Middleware Trong bootstrap/app.php

Laravel tập trung toàn bộ đăng ký middleware trong bootstrap/app.php. Cách tiếp cận này thay thế phương pháp cũ sử dụng app/Http/Kernel.php trước Laravel 11. Fluent API tương tự hoạt động trong Laravel 12 và 13.

bootstrap/app.phpphp
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware) {
        // Global middleware (runs on every request)
        $middleware->append(
            App\Http\Middleware\LogRequestTime::class
        );

        // Add to the 'web' middleware group
        $middleware->web(append: [
            App\Http\Middleware\TrackPageViews::class,
        ]);

        // Add to the 'api' middleware group
        $middleware->api(prepend: [
            App\Http\Middleware\ApiRequestSanitizer::class,
        ]);

        // Register aliases for route-level use
        $middleware->alias([
            'role'       => App\Http\Middleware\EnsureUserHasRole::class,
            'subscribed' => App\Http\Middleware\EnsureUserIsSubscribed::class,
        ]);

        // Control execution order
        $middleware->priority([
            Illuminate\Session\Middleware\StartSession::class,
            Illuminate\Auth\Middleware\Authenticate::class,
            App\Http\Middleware\EnsureUserHasRole::class,
        ]);
    })
    ->create();

Mảng priority có vai trò quan trọng khi nhiều middleware được gán cho cùng một route. Laravel sắp xếp chúng theo danh sách này, đảm bảo session được khởi tạo trước khi xác thực chạy, và xác thực hoàn tất trước khi kiểm tra vai trò.

Thứ Tự Thực Thi Middleware

Middleware chạy theo thứ tự được đăng ký. Đối với middleware cấp route, mảng priority ghi đè thứ tự mặc định. Luôn đặt authentication middleware trước authorization middleware để tránh kiểm tra vai trò trên các request chưa xác thực.

PHP Attributes Cho Middleware Trong Laravel 13

Laravel 13 giới thiệu PHP attribute #[Middleware] để khai báo middleware trực tiếp trên class và method controller. Cách tiếp cận này giữ cấu hình middleware cùng chỗ với code mà nó bảo vệ, giúp các quy tắc ủy quyền dễ đọc và bảo trì hơn.

app/Http/Controllers/CommentController.phpphp
namespace App\Http\Controllers;

use App\Models\Comment;
use App\Models\Post;
use Illuminate\Routing\Attributes\Controllers\Authorize;
use Illuminate\Routing\Attributes\Controllers\Middleware;

#[Middleware('auth')]
class CommentController
{
    #[Middleware('subscribed')]
    #[Authorize('create', [Comment::class, 'post'])]
    public function store(Post $post)
    {
        // Only authenticated, subscribed users who can create comments reach here
    }

    public function index(Post $post)
    {
        // Still requires auth (from class-level attribute)
        return $post->comments;
    }
}

#[Middleware('auth')] ở cấp class áp dụng cho tất cả các method. Các attribute ở cấp method được chồng lên trên: store() yêu cầu cả auth và subscribed. Attribute #[Authorize] tích hợp với hệ thống policy của Laravel, kiểm tra quyền trước khi method thực thi.

Cách tiếp cận dựa trên attribute này là tùy chọn. Middleware trong file route và đăng ký qua bootstrap/app.php vẫn được hỗ trợ đầy đủ. Các nhóm ưa thích định nghĩa route rõ ràng có thể tiếp tục sử dụng fluent API; các nhóm muốn controller tự mô tả có thể áp dụng attribute.

Terminable Middleware Cho Tác Vụ Sau Response

Terminable middleware thực thi logic sau khi response đã được gửi tới client. Điều này rất hữu ích cho việc ghi log, analytics, hoặc các tác vụ dọn dẹp mà không nên chặn người dùng.

app/Http/Middleware/CollectAnalytics.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\Response;

class CollectAnalytics
{
    public function handle(Request $request, Closure $next): Response
    {
        return $next($request);  // Pass through without delay
    }

    public function terminate(Request $request, Response $response): void
    {
        // Runs after response is sent to client
        DB::table('analytics')->insert([
            'path'        => $request->path(),
            'method'      => $request->method(),
            'status_code' => $response->getStatusCode(),
            'user_id'     => $request->user()?->id,
            'ip'          => $request->ip(),
            'created_at'  => now(),
        ]);
    }
}

Phương thức terminate nhận cả request gốc và response cuối cùng. Cần đăng ký middleware này dạng singleton trong AppServiceProvider để đảm bảo cùng một instance xử lý cả handle() và terminate().

Các Pattern Middleware Thực Tế Cho Môi Trường Production

Một số pattern middleware xuất hiện liên tục trong các ứng dụng Laravel ở môi trường production.

Bỏ qua chế độ bảo trì cho phép các IP nội bộ truy cập ứng dụng trong thời gian bảo trì:

app/Http/Middleware/MaintenanceBypass.phpphp
class MaintenanceBypass
{
    private array $allowedIps = ['192.168.1.0/24', '10.0.0.1'];

    public function handle(Request $request, Closure $next): Response
    {
        if (app()->isDownForMaintenance()) {
            foreach ($this->allowedIps as $ip) {
                if ($request->ip() === $ip) {
                    return $next($request);
                }
            }
        }

        return $next($request);
    }
}

Security headers thêm HSTS, content security policy và các header bảo mật khác vào mỗi response:

app/Http/Middleware/SecurityHeaders.phpphp
class SecurityHeaders
{
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        $response->headers->set('X-Content-Type-Options', 'nosniff');
        $response->headers->set('X-Frame-Options', 'SAMEORIGIN');
        $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
        $response->headers->set(
            'Strict-Transport-Security',
            'max-age=31536000; includeSubDomains'
        );

        return $response;
    }
}

Các pattern này minh họa hai vị trí middleware chính: trước request (maintenance bypass kiểm tra IP và có thể chặn truy cập) và sau response (security headers thay đổi response trước khi gửi đi).

Sẵn sàng chinh phục phỏng vấn Laravel?

Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.

Nguồn Tham Khảo

Các Pattern Middleware Laravel Cho Chuẩn Bị Phỏng Vấn

  • Laravel middleware hoạt động như một pipeline: mỗi class xử lý request, tác động lên nó, rồi chuyển tiếp hoặc cắt ngang bằng một response
  • Middleware auth bảo vệ route bằng xác thực dựa trên guard, hỗ trợ nhiều loại người dùng thông qua cú pháp auth:guard
  • Rate limiting thông qua middleware throttle và định nghĩa RateLimiter::for() cho phép kiểm soát truy cập phân tầng dựa trên ngữ cảnh người dùng
  • Custom middleware xử lý các mối quan tâm xuyên suốt như kiểm tra vai trò, làm sạch request và security headers mà không làm rối controller
  • Toàn bộ đăng ký middleware diễn ra tại bootstrap/app.php sử dụng fluent API, với priority kiểm soát thứ tự thực thi
  • Attribute #[Middleware] của Laravel 13 cho phép khai báo middleware trực tiếp trên controller, giữ các quy tắc ủy quyền cùng với handler
  • Terminable middleware chạy các tác vụ sau response (analytics, logging) mà không ảnh hưởng tới độ trễ phía người dùng
  • Tham số middleware qua cú pháp :param giữ cho định nghĩa route rõ ràng và các class middleware có thể tái sử dụng trong nhiều ngữ cảnh khác nhau

Bắt đầu luyện tập!

Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.

Thử thách hôm nay

Bạn có tìm ra lỗi trong Laravel không?

Một đoạn mã thật, một lỗi ẩn, mỗi ngày một lượt. Không cần tài khoản để thử.

Anthony Fillion-Maillet

Viết bởi

Anthony Fillion-Maillet

Người sáng lập SharpSkill

Lập trình viên fullstack hơn 10 năm. Anh điều hành SharpSkill và chịu trách nhiệm về mọi nội dung đăng tại đây.

Cập nhật ngày 21 tháng 9, 2026

Thẻ

#laravel
#middleware
#authentication
#rate-limiting
#php

Chia sẻ

Bài viết liên quan