今天我們來聊聊一個開發中可以用到的工具:Middleware
根據官網所說:
Middleware provide a convenient mechanism for inspecting and filtering HTTP requests entering your application. For example, Laravel includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to your application's login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.
換個說法,Middleware 就像是個過濾器一樣,可以過濾送進來的請求。
要新建 Middleware,我們一樣是透過 artisan
./vendor/bin/sail artisan make:middleware MyMiddleware
跑完之後,我們可以在 app/Http/Middleware/MyMiddleware.php
看到
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class MyMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
return $next($request);
}
}
這邊就是過濾的內容了,我們可以設置一些過濾條件,如果不符合條件就處理掉,然後將通過的請求往下一層送。
要套用規則的話,可以這樣寫
use App\Http\Middleware\MyMiddleware;
Route::get('/', function () {
//
})->middleware(MyMiddleware::class);
我們實際來看看 Laravel 幫我們寫好的一些 Middleware
在 app/Http/Kernel.php
裡面,已經定義了很多我們可以使用在網頁開發上的 Middleware
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array<string, class-string|string>
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
我們挑 Authenticate
這個來看看,打開 app/Http/Middleware/Authenticate.php
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
}
奇怪!內容怎麼這麼少?這裡面的內容顯然不能完成驗證用戶的功能呀?
這是因為,Laravel 這邊的作法,是將驗證用戶主要的程式碼,放在框架套件的程式碼 Illuminate\Auth\Middleware\Authenticate
裡面,然後 App\Http\Middleware\Authenticate
這個類別透過繼承 Illuminate\Auth\Middleware\Authenticate
,可以使用裡面的內容,然後根據開發者的需要,對裡面的內容進行調整,比方說這邊的調整登入失敗時要導向的路徑為何。
這樣的設計,可以避免開發者需要調整功能時,必須要調整 Illuminate
裡面的程式碼,才能客製化自己想要的功能。
如果想繼續看 Illuminate\Auth\Middleware\Authenticate
的程式碼,那麼就是要到 vendor
資料夾裡面找了
在 vendor/laravel/freamework/src/Illuminate/Auth/Middleware/Authenticate.php
內
/**
* Determine if the user is logged in to any of the given guards.
*
* @param \Illuminate\Http\Request $request
* @param array $guards
* @return void
*
* @throws \Illuminate\Auth\AuthenticationException
*/
protected function authenticate($request, array $guards)
{
if (empty($guards)) {
$guards = [null];
}
foreach ($guards as $guard) {
if ($this->auth->guard($guard)->check()) {
return $this->auth->shouldUse($guard);
}
}
$this->unauthenticated($request, $guards);
}
我們就可以開始找到過濾的規則所撰寫的位置了。
看到這邊,有些讀者可能已經想到,Laravel 所提供的這些 Middleware,像是用戶的 Authenticate,似乎在我們前面的一些地方已經被套用過了?
沒錯!其實 Laravel 在一開始的時候,就已經預先幫我們加上一些 Middleware 的處理了!
我們可以在 app/Http/Kernel.php
裡面找到
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' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
這段就是 Laravel 預先設置好的 Middleware 群組
其中 web
會被套用在 web.php
裡面的所有路由中。 api
會被套用在 api.php
的所有路由中。
這也就是 Laravel 實作許多功能,比方說 CSRF Token 驗證,所採取的作法。
今天對 Middleware 的介紹,就先到這邊。各位明天見!