Ra mắt hai series mới cực hot Trí tuệ nhân tạo A đến ZPython công cụ không thể thiếu khi nghiên cứu Data science, Machine learning.

Laravel Middleware cơ chế bộ lọc trung gian

Cơ chế hoạt động của Laravel Middleware

Giới thiệu Laravel Middleware

Middleware đúng như ý nghĩa từ tên gọi của nó, là đoạn code trung gian đứng giữa request và response (xem hình trên), cung cấp một cơ chế bộ lọc. Ví dụ: Laravel cung cấp một middleware để xác nhận xem một người dùng đã xác thực chưa, nếu người dùng đã qua xác thực sẽ được chuyển hướng đến trang quản trị hoặc nếu chưa xác thực sẽ được chuyển đến trang đăng nhập. Tất cả các middleware đều nằm trong thư mục app/Http/Middleware, để tạo một middleware mới sử dụng câu lệnh:

php artisan make:middleware <middleware-name>

Để hiểu rõ hơn middleware chúng ta sẽ bắt đầu với một ví dụ: Tạo một middleware để kiểm tra xem người dùng đủ tuổi đăng ký tài khoản chưa, nếu người dùng lớn hơn 18 tuổi thì sẽ chuyển đến trang quản trị, nếu người dùng chưa đủ tuổi tiếp tục xử lý tiếp.

Bước 1: Tạo middleware với tên là CheckAge

php artisan make:middleware CheckAge
Middleware created successfully.

Bước 2: Sau khi lệnh tạo middleware hoàn thành sẽ tạo ra một file CheckAge.php nằm trong thư muc app/Http/Middleware, thêm đoạn code kiểm tra tuổi như sau:

<?php

namespace Adshare\Http\Middleware;

use Closure;

class CheckAge
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $user = Auth::user();
        if($user->age >= 18){
            return redirect('dashboard');
        }
        return $next($request);
    }
}

Ở đây khi tuổi nhỏ hơn 18 sẽ đơn giản là gọi đến một hàm callback $next với đầu vào là $request tức là nếu nhỏ hơn 18 tuổi thì route áp dụng Middleware này sẽ tiếp tục phần mã trong route. ## Đăng ký Laravel Middleware với hệ thống

Chúng ta cần đăng ký middleware với hệ thống trước khi sử dụng chúng, có hai loại middleware:

  • Global middleware là middleware sẽ được sử dụng với bất kể yêu cầu HTTP đến hệ thống, đơn giản là thêm middleware này vào thuộc tính $middleware trong class app/Http/Kernel.php.
  • Route middleware là gắn một middleware với một route xác định, trước khi gắn một route với một middleware phải liệt kê chúng vào thuộc tính $routeMiddleware trong class app/Http/Kernel.php.

Chúng xem nội dung file app/Http/Kernel.php xem cách đăng ký Middleware:

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{

    protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    ];

    ...
    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,
        <strong>'checkage' => \App\Http\Middleware\CheckAge::class,</strong>
    ];
}

Khi middleware đã được định nghĩa trong HTTP Kernel chúng ta có thể gán chúng với các route:

Route::get('/dashboard', function () {
    // Mã xử lý khác viết ở đây
})->middleware('checkage');

Có thể sử dụng nhiều middleware cho một route

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

Cũng có thể sử dụng đầy đủ tên lớp khi gán Middleware

use App\Http\Middleware\CheckAge;
Route::get('/dashboard', function () {
    //
})->middleware(CheckAge::class);

Truyền tham số cho Middleware

Các middleware cho phép truyền thêm tham số khi được gọi, ví dụ: Người dùng trong hệ thống có rất nhiều vai trò như user, admin, super admin... chúng ta muốn xác thực người dùng dựa trên vai trò thì chúng ta cần truyền tham số cho Middleware. Sau đây chúng ta sẽ thực hành tạo một middleware và truyền tham số cho nó.

Bước 1: Tạo middleware RoleMiddleware

c:\xampp\htdocs\laravel-test>php artisan make:middleware RoleMiddleware
Middleware created successfully.

Nó sẽ tạo ra file RoleMiddleware.php trong app/Http/Middleware, sửa nội dung file này như sau:

<?php
namespace App\Http\Middleware;
use Closure;
class RoleMiddleware
{
    /**
     * Handle the incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string  $role
     * @return mixed
     */
    public function handle($request, Closure $next, $role)
    {
        echo 'Vai trò:' . $role;
        return $next($request);
    }
}

Bước 2: Đăng ký RoleMiddleware trong app/Http/Kernel.php

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,
    <strong>'role' => \App\Http\Middleware\RoleMiddleware::class,</strong>
];

Bước 3: Tạo MainController Laravel Controller sẽ được giới thiệu đến bạn trong bài tiếp theo, trong bài viết này bạn chưa cần hiểu Controller là gì mà cứ thực hiện theo như sau:

c:\xampp\htdocs\laravel-test>php artisan make:controller MainController
Controller created successfully.

Lệnh này sẽ tạo ra file MainController.php nằm trong thư mục app\Http\Controllers, bạn thêm nội dung vào cho file này như sau:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MainController extends Controller
{
    public function checkRole(){
        echo "<br>Main Controller: checkRole function";
   }
}

Bước 4: Gán route cho RoleMiddleware

Route::get('/role',[
   'middleware' => 'role:superadmin',
   'uses' => 'MainController@checkRole',
]);

Bây giờ chạy thử http://laravel.dev/role chúng ta sẽ thấy màn hình sau:

Truyền tham số cho middleware trong Laravel

Chúng ta để ý rằng trong hàm checkRole chúng ta chỉ in ra màn hình mỗi dòng "Main Controller: checkRole function", tuy nhiên ở trang kết quả có thêm dòng "Vai trò:superadmin" do route này đã chạy qua bộ lọc RoleMiddleware và superadmin chính là giá trị từ route truyền vào cho RoleMiddleware.

Nhóm các Middleware

Đôi khi chúng ta muốn nhóm nhiều middleware với một key duy nhất, Laravel cho phép bạn làm điều này, xem thuộc tính middlewareGroups trong file app/Http/Kernel.php:

    /**
     * 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\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

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

Ở đây chúng ta thấy với key "web" đã nhóm lại rất nhiều các Middleware khác nhau. Khi đó gắn middleware cho các route đơn giản như sau:

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

Route::group(['middleware' => ['web']], function () {
    //
});

Terminable Middleware

Đôi khi một Middleware cần làm vài việc sau khi HTTP response được gửi đến trình duyệt, ví dụ một middleware sẽ ghi dữ liệu session vào storage khi HTTP response đã gửi đến trình duyệt. Để làm việc này bạn chỉ cần định nghĩa một hàm tên là terminate trong Middleware đó, nó sẽ được gọi đến khi HTTP response gửi đến trình duyệt. Chúng ta sẽ cùng nhau thực hành: Trong RoleMiddleware ở trên thêm nội dung như sau:

<?php

namespace App\Http\Middleware;

use Closure;

class RoleMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next, $role)
    {
        echo '1. Middleware';
        echo '<br>Vai trò:' . $role;
        echo '<br>Thực hiện khi đang xử lý HTTP response';
        return $next($request);
    }

    public function terminate($request, $response)
    {
        echo '<br>3. Terminable Middleware';
        echo '<br>Thực hiện sau khi HTTP response gửi đến trình duyệt';
    }
}

Vì RoleMiddleware đã được đăng ký ở trong lần thực hành trước nên chúng ta không cần làm thêm gì. Tiếp theo, thay đổi nội dung app/Http/Controllers/MainController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MainController extends Controller
{
    public function checkRole(){
        echo "<br>2. MainController@checkRole";
        echo "<br>Main Controller: checkRole function";
        echo "<br>Thực hiện sau khi qua bộ lọc Middleware và trước khi gửi HTTP response";
   }
}

Ok, chúng ta chạy đường dẫn http://laravel.dev/role sẽ thấy được thứ tự thực hiện các thành phần:

Terminable Middleware trong Laravel

Vậy là bạn đã nắm được khái niệm về Middleware trong Laravel cũng như thứ tự thực hiện các đoạn code, phải công nhận Laravel đưa ra các khái niệm rất đơn giản, dễ hiểu, dễ áp dụng và đặc biệt nó kiểm soát được tất cả các trạng thái từ khi phát sinh một yêu cầu tải trang đến khi kết thúc trả về kết quả cho trình duyệt. Trong bài viết có nhắc đến Controller và còn để ngỏ, chúng ta sẽ tìm hiểu Laravel Controller trong loạt bài kế tiếp.


CÁC BÀI VIẾT KHÁC

FirebirD

Đam mê Toán học, Lập trình. Sở thích chia sẻ kiến thức, Phim hài, Bóng đá, Cà phê sáng với bạn bè.

Cài đặt Laravel nhanh cho hệ điều hành Windows

Laravel Controller trung tâm điều khiển hệ thống

12 Bình luận trong "Laravel Middleware cơ chế bộ lọc trung gian"

  1. Đại

    5 years ago

    Phản hồi
    Một trang hữu ích, hy vọng tác giả có thêm nhiều bài viết hữu ích hơn nữa
  2. viyouen

    4 years ago

    Phản hồi
    hàm terminate() mình làm nó không chạy, trên hình không thấy gọi ở đâu hết vậy ad
    1. FirebirD

      4 years ago

      Phản hồi
      Có đoạn: "Vì RoleMiddleware đã được đăng ký ở trong lần thực hành trước nên chúng ta không cần làm thêm gì." Bạn xem lại "Bước 2: Đăng ký RoleMiddleware trong app/Http/Kernel.php".
  3. thinguyen

    4 years ago

    Phản hồi
    mình làm tới đây nhưng mà khi chạy nó báo lỗi " Bây giờ chạy thử http://laravel.dev/role chúng ta sẽ thấy màn hình sau: " chạy lên nó báo lỗi là " ReflectionException Function () does not exist " là do sao vậy add
  4. huy

    3 years ago

    Phản hồi

    website mới đẹp, nhưng nhìu hình bị lỗi quá ad ơi. Mong ad sớm fix

    1. FirebirD

      3 years ago

      Phản hồi

      Thanks Huy, ae đang rà soát lại nội dung, rất cám ơn những độc giả như bạn. Do chuyển đổi nền tảng từ Wordpress sang OctoberCMS có khá nhiều điểm khác biệt nên phải xử lý dần.

  5. kien

    3 years ago

    Phản hồi

    hình ảnh bị mất hết

  6. Phú

    3 years ago

    Phản hồi

    có lệnh tạo mới middleware mà không nói viết lệnh ở đâu vậy admin ?

  7. Sang

    3 years ago

    Phản hồi

    Dư css bên dưới , chỗ Middleware Group thường dùng trong trường hợp nào chưa rõ lắm, admin thêm ví dụ càng hay 'role' => \App\Http\Middleware\RoleMiddleware::class, 'checkage' => \App\Http\Middleware\CheckAge::class,

  8. T

    2 years ago

    Phản hồi

    Route::get('/role',[ 'middleware' => 'role:superadmin', 'uses' => 'MainController@checkRole', ]); phần này em chưa hiểu lắm , vì sao khi xóa uses hoặc role: này thì nó lại báo lỗi , còn xóa middleware thì vẫn chạy bình thường ạ. a có thể giải thích kỹ cho em với ạ

  9. Yayaya

    2 years ago

    Phản hồi

    Chào bạn. Đến laravel 8 thì route bị thay đổi nên xảy ra lỗi ở đoạn Bước 4: Gán route cho RoleMiddleware Route::get('/role',[ 'middleware' => 'role:superadmin', 'uses' => 'MainController@checkRole', ]); , sửa thành use App\Http\Controllers\MainController; Route::get('/role',[ MainController::class, //Controller 'checkRole', //function trong controller ])->middleware('role:superadmin');

  10. Nguyễn Tiến Mạnh

    1 year ago

    Phản hồi

    em không chạy được từ chỗ maincontroller nó báo Target class [MainController] does not exist.

Thêm bình luận