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 𝑛𝑒𝑥𝑡𝑣ớ𝑖đầ𝑢𝑣à𝑜𝑙ànextvớiđầuvàolà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>
];
}
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:
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:
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.