Middleware trong laravel
Bài đăng này đã không được cập nhật trong 8 năm
Giới thiệu
Middleware cung cấp một giải pháp khá tiện ích cho việc filtering HTTP các requests vào ứng dụng. Ví dụ, Laravel có chứa một middleware xác thực người dùng đăng nhập vào hệ thống. Nếu user chưa đăng nhập, middleware sẽ chuyển hướng user tới màn hình đăng nhập. Tuy nhiên, nếu user đã đăng nhập rồi, thì 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ụ nữa ngoài kiểm tra đăng nhập vào hệ thống. Một CORS middleware có trách nhiệm cho việc thêm các header hợp lý vào trong tất cả các response gửi ra ngoài. Một logging middleware có thể ghi log cho tất cả các request tới ứng dụng.
Có vài middleware đã có sẵn trong Laravel framework, bao gồm middlware xác thực, CSRF protection. Tất cả được nằm trong thư mục app/Http/Middleware
.
Tạo Middleware
Để tạo mới một middleware, sử dụng lệnh make:middleware
:
php artisan make:middleware CheckAge
Câu lệnh này sẽ tạo ra class CheckAge
bên trong thư mục app/Http/Middleware
. Trong middleware này, chúng ta chỉ cho phép truy cập vào route nếu giá trị age
lớn hơn 200. Ngược lại, chúng ta sẽ chuyển hướng request lại trang home
URI.
<?php
namespace App\Http\Middleware;
use Closure;
class CheckAge
{
public function handle($request, Closure $next)
{
if ($request->age <= 200) {
return redirect('home');
}
return $next($request);
}
}
Như bạn thấy, nếu biến age
nhỏ hơn hoặc bằng 200
, middleware sẽ trả về một HTTP tới client; ngược lại, request sẽ được gửi tiếp để xử lý. Để 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 callback $next
với $request
.
Tốt nhất hãy hình dung như là một chuỗi các "lớp" trên HTTP requests cần phải đi qua trước khi nó vào ứng dụng. Mỗi lớp sẽ được kiểm tra request và thậm chí có thể hủy từ chối request hoàn toàn.
Trước & Sau Middleware
Việc middleware chạy trước hay chạy sau một request phụ thuộc vào chính nó. Ví dụ, middleware dưới đây sẽ làm một vào 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);
}
}
Tất nhiên, middleware này sẽ thực hiện việc 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;
}
}
Đăng ký 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 thêm tên class của middleware trong thuộc tính $middleware
của class app/Http/Kernel.php
.
Gán Middleware vào Routes
Nếu bạn muốn gán middleware cho route cụ thể, đầu tiên bạn cần thêm middleware đấy vào trong file app/Http/Kernel.php
. Mặc định, thuộc tính $routeMiddleware
sẽ chứa một số class thuộc middleware của framework 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,
];
Khi middleware đã được định nghĩa trong HTTP kernel, bạn có thể sử dụng phương thức middleware
gán cho một route:
Route::get('admin/profile', function () {
//
})->middleware('auth');
Ngoài ra bạn cũng có thể gán nhiều middleware cho một route:
Route::get('/', function () {
//
})->middleware('first', 'second');
Khi đã gán middleware, bạn cũng có thể sử dụng tên đầy đủ của middleware:
use App\Http\Middleware\CheckAge;
Route::get('admin/profile', function () {
//
})->middleware(CheckAge::class);
Nhóm Middleware
Thỉnh thoảng bạn muốn nhóm một vài middleware lại trong một khóa để 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.
Mặc định, Laravel cung cấp sắp 2 nhóm middleware web
và api
chứa những middleware thường sử dụng mà bạn có thể muốn áp dụng cho web UI và API routes:
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',
],
];
Nhóm middleware được gán vào routes và controller sử dụng cú pháp tương tự như với từng middleware. Một lần nữa, nhóm middleware 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 () {
//
});
Tham số middleware
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ẽ dượ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
{
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 thao số thì phân chia bởi dấy phẩy:
Route::put('post/{id}', function ($id) {
//
})->middleware('role:editor');
Terminable Middleware
Thỉnh thoảng 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 đi kèm với Laravel cung cấp 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 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...
}
}
Hàm terminate
sẽ nhận cả request và response. Khi bạn đã định nghĩa terminable middleware, bạ phải thêm nó vào trong danh sách global middleware trong HTTP kernel.
Khi gọi hàm terminate
trong middleware, Laravel sẽ thực hiện giải quyết trường hợp mới cho middleware từ service container. Nếu bạn muốn sử dụng cùng một trường hợp khi mà hàm handle
và hàm terminate
được gọi, đăng ký middleware vào trong container sử dụng hàm singleton
.
All rights reserved