Laravel: Tìm hiểu về Middleware
Bài đăng này đã không được cập nhật trong 6 năm
Introduction
Middleware cung cấp một giải pháp khá tiện ích cho việc filtering HTTP các requests trong ứng dụng của bạn. Ví dụ, Laravel có chứa một middleware xác thực user đăng nhập vào ứng dụng của bạn được chứng thực. Nếu user chưa được chứng thực, middleware sẽ chuyển hướng (redirect) user tới màn hình đăng nhập. Tuy nhiên, nếu user đã được chứng thực, middleware sẽ cho phép request được thực hiện tiếp tiến trình xử lý vào ứng dụng.
Tất nhiên, bạn có thể viết thêm middleware để thực hiện nhiều tác vụ khác ngoài việc xác thực vào hệ thống. Một CORS middleware có trách nhiệm thêm các header thích hợp vào trong tất cả các response gửi ra ngoài ứng dụng của bạn. Một logging middleware có thể ghi log cho tất cả các request tới ứng dụng của bạn.
Có một số middleware đã có sẵn trong Laravel framework, bao gồm middlware xác thực và CSRF protection. Tất cả các middleware này đều được nằm trong thư mục app/Http/Middleware.
Defining Middleware
Để tạo mới một middleware, sử dụng câu lệnh artisan make:middleware
:
php artisan make:middleware CheckAge
Câu lệnh này sẽ đặt 1 class mới CheckAge
trong thư mục app/Http/Middleware
. Trong middleware này, chúng ta chỉ cho phép truy cập đến route nếu cung cấp age
lớn hơn 200. Nếu không thì, chúng ta sẽ chuyển hướng user trở lại trang home
.
<?php
namespace App\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)
{
if ($request->age <= 200) {
return redirect('home');
}
return $next($request);
}
}
Như bạn thấy, nếu age
nhỏ hơn hoặc bằng 200, middleware sẽ trả về một HTTP redirect tới client; nếu không thì, request sẽ được chuyển tiếp vào ứng dụng của bạn. Để truyền request vào sâu hơn trong ứng dụng (cho phép middleware "vượt qua"), đơn giản chỉ cần gọi $next
callback với $request
.
Tốt nhất hãy hình dung middleware như một chuỗi các "lớp" HTTP requests phải vượt qua trước khi vào ứng dụng. Mỗi lớp sẽ được kiểm tra request và thậm chí có thể từ chối request hoàn toàn.
Before & After Middleware
Việc middleware chạy trước hay chạy sau một request phụ thuộc vào middleware đó. Ví dụ, middleware sau sẽ thực hiện một số tác vụ trước khi request được chương trình xử lý:
<?php
namespace App\Http\Middleware;
use Closure;
class BeforeMiddleware
{
public function handle($request, Closure $next)
{
// Perform action
return $next($request);
}
}
Tuy nhiên, middleware này sẽ thực hiện nhiệm vụ của nó sau khi request được xử lý bởi ứ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;
}
}
Registering Middleware
Global Middleware
Nếu bạn muốn một middleware có thể thực thi trong mọi HTTP request tới ứng dụng của bạn, đơn giản chỉ cần liệt kê tên class middleware trong thuộc tính $middleware
của class app/Http/Kernel.php
.
Assigning Middleware To Routes
Nếu bạn muốn gán middleware cho route cụ thể, đầu tiên bạn cần thêm middleware đó là 1 key trong file app/Http/Kernel.php
. Mặc định, thuộc tính $routeMiddleware
chứa một số class middleware có sẵn trong Laravel. Để thêm middleware của bạn, đơn giản chỉ là thêm nó vào dach sách và gán từ khóa bạn chọn. Ví dụ:
// Within App\Http\Kernel 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,
];
Mỗi middleware được định nghĩa trong HTTP kernel, bạn có thể sử dụng phương thức middleware
để chỉ định middleware cho một route:
Route::get('admin/profile', function () {
//
})->middleware('auth');
Bạn cũng có thể chỉ định nhiều middleware cho route:
Route::get('/', function () {
//
})->middleware('first', 'second');
Khi chỉ định middleware cho route, bạn cũng có thể sử dụng tên đầy đủ của class middleware:
use App\Http\Middleware\CheckAge;
Route::get('admin/profile', function () {
//
})->middleware(CheckAge::class);
Middleware Groups
Đôi khi có thể bạn muốn nhóm một vài middleware lại trong một key để thực hiện gán vào route dễ dàng hơn. Bạn có thể sử dụng thuộc tính ```$middlewareGroups``` của HTTP kernel.
Ngoài ra, Laravel đi kèm với các nhóm middleware web
và api
có chứa các middleware phổ biến mà bạn có thể áp dụng cho giao diện người dùng trên các route web
và các api
của mình:
/**
* 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',
],
];
middleware group được gán vào routes và controller sử dụng cú pháp tương tự như với middleware đơn lẻ. Một lần nữa, middleware group làm đơn giản trong việc gán các middleware vào trong một route:
Route::get('/', function () {
//
})->middleware('web');
Route::group(['middleware' => ['web']], function () {
//
});
Middleware Parameters
Middleware cũng có thể nhận thêm các tham số truyền vào. Ví dụ, nếu ứng dụng của bạn cần xác thực có "role" cụ thể trước khi thực hiện một thao tác nào đó, bạn có thể tạo một CheckRole
middleware để nhận tên của role như một tham số.
Thêm các tham số middleware sẽ được truyền vào middleware ngay sau tham số $next
của hàm handle:
<?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 khai báo trên route bằng cách phân chia tên middleware và tham số bởi dấu :
. Nhiều tham số thì cần được phân chia bởi dấy phẩy:
Route::put('post/{id}', function ($id) {
//
})->middleware('role:editor');
Terminable Middleware
Đôi khi một middleware có thể cần thực hiện sau khi HTTP response đã được gửi xong cho trình duyệt. Ví dụ, "session" middleware có trong Laravel ghi dữ liệu session cho storage sau khi response được gửi tới trình duyệt. Nếu bạn định nghĩa một phương thức terminate
vào trong middleware, nó sẽ tự động được gọi sau khi response được gửi tới 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)
{
// Store the session data...
}
}
Phương thức terminate
có thể nhận cả request và response. Mỗi khi bạn định nghĩa terminable middleware, bạn cần thêm vào danh sách global middleware trong file app/Http/Kernel.php
.
Khi bạn gọi hàm terminate
trong middleware, Laravel sẽ giải quyết instance mới cho middleware từ service container. Nếu bạn muốn sử dụng cùng một middleware instance khi mà phương thức handle
và terminate
được gọi, hãy đăng ký middleware vào trong container sử dụng phương thức singleton
.
All rights reserved