Laravel: Middleware

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

MỤC LỤC BÀI VIẾT:

Giới thiệu

Middleware cung cấp một cơ chế thuận tiện cho việc lọc các yêu cầu HTTP vào ứng dụng của bạn. Ví dụ, Laravel bao gồm một middleware xác minh người dùng của ứng dụng của bạn được xác thực. Nếu người dùng không xác thực, middleware sẽ chuyển hướng người dùng đến màn hình đăng nhập.Tuy nhiên, nếu người dùng được xác thực, middleware sẽ cho phép các yêu cầu tiến sâu hơn vào ứng dụng.

Tất nhiên, middleware bổ sung có thể được viết để thực hiện một loạt các nhiệm vụ bên cạnh việc xác thực. Middleware CORS có thể chịu trách nhiệm cho việc thêm các tiêu đề thích hợp cho tất cả các câu trả lời để lại trên ứng dụng của bạn. Middleware đăng nhập có thể đăng nhập tất cả các yêu cầu đến ứng dụng của bạn.

Có một số middleware đặt trong framework Laravel, bao gồm middleware để xác thực và bảo vệ CSRF. Tất cả các middleware được đặt trong thư mục app/Http/Middleware.

Định nghĩa middleware

Để tạo ra một middleware mới ta sử dụng lệnh Artisan make:middleware:

php artisan make:middleware CheckAge

Lệnh này sẽ đặt một lớp mới CheckAge trong của thư mục app/Http/Middleware. Trong middleware này, ta sẽ chỉ cho phép truy cập vào các route nếu age lớn hơn 200. Nếu không, chúng ta sẽ chuyển hướng người dùng trở lại URI home.

<?php

namespace App\Http\Middleware;

use Closure;

class CheckAge
{
    /**
     * Run the request filter.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->age <= 200) {
            return redirect('home');
        }

        return $next($request);
    }

}

Như bạn có thể thấy, nếu age ít hơn hoặc bằng 200, thì middleware sẽ quay trở lại một chuyển hướng HTTP cho khách hàng; nếu không, các yêu cầu sẽ được chuyển tiếp vào ứng dụng. Để vượt qua các yêu cầu sâu hơn vào các ứng dụng (cho phép middleware "vượt qua"), thì ta gọi callback $next với $request.

Nó là tốt nhất để hình dung middleware như là một loạt các các yêu cầu HTTP "lớp" phải đi qua trước khi họ nhấn ứng dụng của bạn. Mỗi lớp có thể kiểm tra các yêu cầu và thậm chí từ chối nó hoàn toàn.

Trước và sau middleware

Một middleware chạy trước hay sau một yêu cầu phụ thuộc vào bản thân middleware đó. Ví dụ, middleware sau đây sẽ thực hiện một số nhiệm vụ trước khi yêu cầu được xử lý bởi các ứng dụng:

<?php

namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware
{
    public function handle($request, Closure $next)
    {
        // Perform action

        return $next($request);
    }
}

Tuy nhiên, middleware sau sẽ thực hiện nhiệm vụ của mình sau khi yêu cầu được xử lý bởi các ứng dụng:

<?php

namespace App\Http\Middleware;

use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        // Perform action

        return $response;
    }
}

Đăng ký Middleware

Middleware global

Nếu bạn muốn có một middleware để chạy trong mọi yêu cầu HTTP tới ứng dụng của bạn, bạn chỉ cần liệt kê các lớp middleware trong thuộc tính $middleware của lớp app/Http/Kernel.php.

Gán middleware cho route

Nếu bạn muốn gán middleware cho các route cụ thể thì trước tiên bạn nên gán cho middleware một key trong của tập tin app/Http/Kernel.php. Theo mặc định, thuộc tính $routeMiddleware của lớp này có chứa các mục cho middleware đã có trong Laravel. Nếu bạn muốn thêm riêng thì chỉ cần thêm nó vào danh sách này và gán cho nó một key. Ví dụ:

// Bên trong lớp App\Http\Kernel ...

protected $routeMiddleware = [
    'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];

Một khi middleware đã được định nghĩa trong HTTP kernel thì bạn có thể sử dụng phương thức middleware để gán middleware vào một route:

Route::get('admin/profile', function () {
    //
})->middleware('auth');

Bạn cũng có thể gán nhiều middleware vào route:

Route::get('/', function () {
    //
})->middleware('first', 'second');

Khi gán middleware thì bạn cũng có thể dùng tên lớp đầy đủ:

use App\Http\Middleware\CheckAge;

Route::get('admin/profile', function () {
    //
})->middleware(CheckAge::class);

Khi gán middleware cho một nhóm các route, đôi khi bạn có thể cần ngăn middleware áp dụng cho một route riêng lẻ trong nhóm. Bạn có thể thực hiện điều này bằng phương thức withoutMiddleware:

use App\Http\Middleware\CheckAge;

Route::middleware([CheckAge::class])->group(function () {
    Route::get('/', function () {
        //
    });

    Route::get('admin/profile', function () {
        //
    })->withoutMiddleware([CheckAge::class]);
});

Phương thức withoutMiddleware chỉ có thể loại bỏ middleware route và không áp dụng được cho middleware global.

Nhóm middleware

Đôi khi bạn có thể muốn nhóm nhiều middleware dưới một key duy nhất để làm cho chúng dễ dàng hơn trong việc gán cho các route. Bạn có thể làm điều này bằng cách sử dụng thuộc tính $middlewareGroups của HTTP kernel.

Ra khỏi hộp, Laravel đi kèm với nhóm các middleware web và api phổ biến, bạn có thể muốn áp dụng cho giao diện người dùng web của bạn và các route API:

/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'auth:api',
    ],
];

Các nhóm middleware có thể được giao cho các route và hành động controller bằng cách sử dụng cú pháp giống như middleware đơn lẻ. Một lần nữa, các nhóm middleware chỉ đơn giản là làm cho nó thuận tiện hơn để gán nhiều middleware cùng lúc tới một route:

Route::get('/', function () {
    //
})->middleware('web');

Route::group(['middleware' => ['web']], function () {
    //
});
 
Ra khỏi hộp, nhóm middleware web được tự động áp dụng cho file routes/web.php trong RouteServiceProvider.

Sắp xếp middleware

Hiếm khi, bạn có thể cần middleware thực thi theo một thứ tự cụ thể nhưng không có quyền kiểm soát thứ tự của chúng khi chúng được chỉ định cho route. Trong trường hợp này, bạn có thể chỉ định mức độ ưu tiên middleware bằng cách sử dụng thuộc tính $middlewarePriority của file app/Http/Kernel.php:

/**
 * The priority-sorted list of middleware.
 *
 * This forces non-global middleware to always be in the given order.
 *
 * @var array
 */
protected $middlewarePriority = [
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
    \Illuminate\Routing\Middleware\ThrottleRequests::class,
    \Illuminate\Session\Middleware\AuthenticateSession::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \Illuminate\Auth\Middleware\Authorize::class,
];

Các tham số middleware

Middleware cũng có thể nhận được các tham số bổ sung. Ví dụ, nếu ứng dụng của bạn cần phải xác minh rằng người dùng xác thực có một "vai trò" được đưa ra trước khi thực hiện một hành động nào đó, bạn có thể tạo ra một middleware CheckRole tiếp nhận một tên vai trò như một tham số bổ sung.

Tham số middleware bổ sung sẽ được chuyển đến middleware sau đối số $next:

<?php

namespace App\Http\Middleware;

use Closure;

class CheckRole
{
    /**
     * Handle the incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string  $role
     * @return mixed
     */
    public function handle($request, Closure $next, $role)
    {
        if (! $request->user()->hasRole($role)) {
            // Redirect...
        }

        return $next($request);
    }

}

Tham số middleware có thể được xác định khi định nghĩa route bằng cách tách tên middleware và các tham số sử dụng dấu :. Nếu có nhiều tham số dùng dấu phẩy để phân tách:

Route::put('post/{id}', function ($id) {
    //
})->middleware('role:editor');

Có thể kết thúc Middleware

Đôi khi một middleware có thể cần phải làm một số công việc sau khi các phản ứng HTTP đã được gửi đến trình duyệt. Nếu bạn định nghĩa một phương thức terminate trên middleware và web server của bạn sử sụng FastCGI thì nó sẽ tự động được gọi sau khi hồi đáp được gửi đến trình duyệt.

<?php

namespace Illuminate\Session\Middleware;

use Closure;

class StartSession
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }

    public function terminate($request, $response)
    {
        // Lưu trữ dữ liệu
 session
...
    }
}

Phương thức terminate nên nhận được cả yêu cầu và hồi đáp. Một khi bạn đã định nghĩa một middleware có thể kết thúc, bạn nên thêm nó vào danh sách các route hoặc middleware global trong file app/Http/Kernel.php.

Khi gọi phương thức terminate trên middleware, Laravel sẽ giải quyết một trường hợp mới của middleware từ service container. Nếu bạn muốn sử dụng các thể hiện middleware tương tự nhau khi các phương thức handle terminate được gọi, bạn hãy đăng ký middleware với container sử dụng phương thức singleton của container.

» Tiếp: Bảo vệ CSRF
« Trước: Route (Định tuyến)
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!