[Laravel]使用 Middleware 來集中管理身分驗證

Kunyu
6 min readMar 3, 2024
Photo by Aleksey Oryshchenko on Unsplash

網站通常有很多功能是必須登入之後才能查看的頁面,也就是說使用者必須通過身分驗證,PHP 常見的方法是當使用者成功登入後,將其身分資訊儲存在 session 中。然後,在每個頁面的開頭檢查 session 中是否存在有效的身分認證。如果不存在,則導向登入頁面。

// 在每個頁面的開頭
session_start();

if (!isset($_SESSION['user_id'])) {
header("Location: login.php"); // 導向登入頁面
exit;
}

Laravel MVC 架構雖然也可以使用這樣的邏輯來驗證,不過在每個 Controllers Method 都寫上這樣的驗證邏輯是有點累人的。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostController extends Controller
{
// Controller Method 一開頭先判斷身分驗證
public function showCreateForm()
{
if (!auth()->check()) {
return redirect('/');
}
return view('create-post');
}
}

Laravel 可以使用更優雅的方式來處理,因為在 Laravel 當中,使用者的 request 在被 routes 分配到 Controller 之後,會先通過 Middleware,因此我們可以將身分認證這件事情放在 Middleware 來處理,這樣做可以使Controller Method 保持乾淨且專注於業務邏輯。這種方式也符合常見的設計原則,例如單一職責原則(SRP)和分離關注點(SoC),使得程式碼更易於理解、擴展和維護。

Route::get('/', [UserController::class, 'showCorrectHomepage']);
Route::post('/register', [UserController::class, 'register'])->middleware('guest');
Route::post('/login', [UserController::class, 'login'])->middleware('guest');
Route::post('/logout', [UserController::class, 'logout'])->middleware('auth');

Route::get('/create-post', [PostController::class, 'showCreateForm'])->middleware('auth');
Route::post('/create-post', [PostController::class, 'storeNewPost'])->middleware('auth');

自定義身分認證邏輯

由於 auth、guest 都是 Laravel 所內建的 Middleware,不一定會符合專案需求,這時候我們就可以透過自定義 Middleware 來把身分認證調整成符合專案的內容。

(1) 使用 artisan 指令建立一個 Middleware。

php artisan make:middleware MustBeLoggedIn

(2) 撰寫驗證邏輯,如果通過身分認證,要把 request 往後送 (next)。

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class MustBeLoggedIn
{
public function handle(Request $request, Closure $next): Response
{
if ($request->session()->has('user_id')) {
return $next($request);
}
return redirect('/')->with('failure', '您必須登入系統。');
}
}

(3) Kernel 註冊 Middleware,大功告成。

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
protected $middlewareAliases = [

// 自定義 middleware
'mustBeLoggedIn' => \App\Http\Middleware\MustBeLoggedIn::class,

// Laravel 內建
'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,
'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
}

--

--