Giới thiệu
-
Middleware là những đoạn mã trung gian nằm giữa các request và response. Nó nhận các request, thi hành các mệnh lệnh tương ứng trên request đó. Sau khi hoàn thành nó response (trả về) hoặc chuyển kết quả ủy thác cho một Middleware khác trong hàng đợi.
-
Middleware như là một cơ chế cho phép bạn tham gia vào luồng xử lý request của một ứng dụng Laravel. Trong một quá trình xử lý route điển hình của Laravel khi thực thi việc xử lý yêu cầu và middleware là một trong những class mà ứng dụng phải thông qua.
-
VD: middleware Authenticate có tác dụng kiểm tra xem người dùng đang thực thi request đã đăng nhập hay chưa? Nếu chưa đăng nhập thì sẽ redirect về trang login và ngược lại đăng nhập rồi thì sẽ cho phép thực hiện request.
1.Khởi tạo Middleware
Để tạo 1 middleware mới chúng ta có thể sử dụng câu lệnh sau:
php artisan make:middleware EnsureTokenIsValid
Lúc này Laravel sẽ sinh ra cho bạn một file middleware nằm trong thư mục app/Http/Middleware
với tên file là tên class middleware là EnsureTokenIsValid:
<?php namespace App\Http\Middleware; use Closure; class EnsureTokenIsValid
{ /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { if ($request->input('token') !== 'my-secret-token') { return redirect('home'); } return $next($request); }
}
Trong middleware này bạn có thể thấy nếu token gửi lên từ request không khớp với token đã có thì request sẽ redirect về màn hình home. Ngược lại nếu thoả mãn thì nó sẽ cho phép request được tiếp tục
- Middleware có thể được thực thi trước hoặc sau khi request được xử lý. Như ở ví dụ trên là Middleware thực thi trước khi xử lý request tiếp theo. Còn sau đây là ví dụ về việc thực thi sau khi request được xử lý:
<?php namespace App\Http\Middleware; use Closure; class EnsureTokenIsValid
{ /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $response = $next($request); // Log the request and response details Log::info('Request: ' . $request->url()); Log::info('Response: ' . $response->status()); return $response; }
}
Ở ví dụ này Middleware đã log lại lại các request url và response status sau khi request được xử lý
2.Đăng ký Middleware
2.1 Global Middleware
Khi bạn muốn tất cả các request đều phải đi qua 1 middleware nào đó thì bạn có thể thêm nó vào mảng $middleware trong app/Http/Kernel.php
class:
2.2 Áp dụng Middleware cho route
Để áp dụng middleware cho 1 route cụ thể nào đó, bạn chỉ cần gọi đến method middleware khi khai báo route:
use App\Http\Middleware\Authenticate; Route::get('/profile', function () { // ...
})->middleware(Authenticate::class);
Hoặc bạn có thể áp dụng nhiều middleware cho cùng 1 route như sau:
Route::get('/', function () { // ...
})->middleware([First::class, Second::class]);****
Để ngắn gọn hơn bạn có thể đặt tên cho middleware của bạn và sử dụng tên đó khi khai báo route. Việc đặt tên đó được viết trong app/Http/Kernel.php
với $middlewareAliases property:
// Within App\Http\Kernel class... protected $middlewareAliases = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
Sau đó bạn có thể sử dụng nó như sau:
Route::get('/profile', function () { // ...
})->middleware('auth');
2.3 Áp dụng Middleware cho group route
Khi bạn muốn áp dụng middleware cho nhiều route bạn có thể gộp các route đó thành group và áp dụng middleware cho group đó. Bạn cũng có thể áp dụng được nhiều middleware cho 1 group:
Route::middleware(['verified','auth'])->group(function () { // ...
});
Có trường hợp bạn sử dụng middleware cho 1 nhóm route nào đó nhưng có 1 route bạn không muốn áp dụng middleware đó bạn có thể sử dụng tới method withoutMiddleware:
Route::middleware(['verified','auth'])->group(function () { Route::get('/', function () { // ... }); Route::get('/profile', function () { // ... })->withoutMiddleware(['verified']);
});
Bạn cũng có thể sử dụng withoutMiddleware cho group route
withoutMiddleware chỉ áp dụng được với route middleware, không áp dụng được cho global middleware
2.4 Sắp xếp Middleware
Thông thường middleware sẽ được thực thi theo thứ tự từ trên xuống. Nhưng nếu bạn muốn thay đổi thứ tự ưu tiên của một middleware nào đó. Bạn có thể thêm vào trong thuộc tính $middlewarePriority trong file app/Http/Kernel.php
.
protected $middlewarePriority = [ \Illuminate\Cookie\Middleware\EncryptCookies::class, \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,
];
3. Middleware Parameters
Middleware cũng có thể nhận được tham số truyền vào. Ví dụ với trường hợp: ứng dụng của bạn cần xác định role của người dùng là gì trước khi thực thi . Ví dụ với EnsureUserHasRole middleware dưới đây:
<?php namespace App\Http\Middleware; use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response; class EnsureUserHasRole
{ /** * Handle an incoming request. * * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ public function handle(Request $request, Closure $next, string $role): Response { if (! $request->user()->hasRole($role)) { // Redirect... } return $next($request); } }
Và khi khai báo route để truyền tham số vào cho middleware bạn sử dụng dấu : nếu có nhiều tham số thì ngăn cách nhau bằng dấu phẩy:
Route::put('/post/{id}', function (string $id) { // ...
})->middleware('role:editor');