你的 Laravel API 正在裸奔嗎?終極驗證 (Validation) 與中介層 (Middleware) 客製化聖經,打造駭客也搖頭的銅牆鐵壁

2025/12/14 | Laravel技術分享, 全端與程式開發, 技術教學資源

駭客也搖頭!Laravel API 終極驗證與中介層客製化防禦聖經

你的 Laravel API 仍在「裸奔」嗎?資深工程師 Eric 警告,資料驗證 (Validation) 與請求過濾 (Middleware) 是 API 的兩道生命線。本文將教你如何超越基礎 required 規則,客製化如台灣身分證字號的驗證邏輯,並打造帶參數的彈性 Middleware 進行精準權限控管。這不僅是優化程式碼,更是建立讓駭客難以攻破的銅牆鐵壁。立即掌握這些專業技巧,擺脫「義大利麵」程式碼,將你的專案提升到企業級安全層次!

需要專業協助?

聯絡浪花專案團隊 →

你的 Laravel API 正在裸奔嗎?終極驗證 (Validation) 與中介層 (Middleware) 客製化聖經,打造駭客也搖頭的銅牆鐵壁

嗨,我是浪花科技的資深工程師 Eric。寫了這麼多年的程式,我看過太多專案因為一個小小的疏忽而門戶大開,尤其是在 API 開發的世界裡。很多工程師覺得 API 只要能動、能回傳 JSON 就好,卻忽略了最重要的兩道防線:資料的「驗證 (Validation)」與請求的「過濾 (Middleware)」。

這就像蓋了一棟豪宅,卻裝了個紙糊的大門,還忘了請保全。任何阿貓阿狗都能隨便進出,甚至在你家裡塗鴉、搬走你的家具。今天,我就要以一個老工程師的囉嗦精神,帶你深入探討 Laravel 驗證與 Middleware 客製化 的藝術,不只是教你怎麼用,更是要教你如何打造一個讓駭客看到都想繞道的堅固防線。

第一道防線:Laravel 驗證 (Validation) – 不只是 `required` 這麼簡單

「Garbage in, garbage out.」這句古老的工程師諺語,點出了驗證的核心價值。如果你的應用程式從一開始就接收了格式錯誤、不合邏輯的垃圾資料,那後續的商業邏輯再怎麼天花亂墜,產出的結果也只會是一場災難。Laravel 內建的驗證器非常強大,但真正的戰場往往在那些內建規則無法觸及的灰色地帶。

為何 Validation 是你的第一道防線?

想像一下,使用者註冊時,你要求輸入手機號碼,但沒有驗證格式,結果資料庫裡存了一筆「我的手機號碼是這個」。當你需要發送簡訊驗證碼時,系統就直接崩潰了。Validation 的目的,就是在這些髒資料接觸到你核心的商業邏輯或寫入資料庫之前,就把它們優雅地擋在門外,並給予使用者明確的提示。

超越基礎:打造你的客製化驗證規則 (Custom Validation Rules)

當內建的 `email`, `numeric`, `max:255` 不夠用時,就是我們捲起袖子自己動手的時候了。例如,你需要驗證一個台灣的身分證字號,這顯然沒有內建規則可以用。這時候,`php artisan make:rule` 就是你的好朋友。

假設我們要建立一個 `TaiwanIdNumber` 的驗證規則:

php artisan make:rule TaiwanIdNumber

接著 Laravel 會在 `app/Rules` 資料夾下產生一個 `TaiwanIdNumber.php` 檔案。我們需要實作 `passes` 方法(驗證邏輯)和 `message` 方法(錯誤訊息):

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class TaiwanIdNumber implements Rule
{
    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        $value = strtoupper($value);

        if (!preg_match('/^[A-Z][12]\d{8}$/', $value)) {
            return false;
        }

        // 這是一個簡化的檢查碼驗證邏輯,僅供示範
        $idHeader = 'ABCDEFGHJKLMNPQRSTUVWXYZIO';
        $idHeaderMap = str_split($idHeader);
        $map = array_flip($idHeaderMap);
        $n1 = floor(($map[$value[0]] + 10) / 10);
        $n2 = ($map[$value[0]] + 10) % 10;

        $nums = str_split(substr($value, 1));
        $sum = $n1 + ($n2 * 9);
        for ($i = 0; $i < 8; $i++) {
            $sum += $nums[$i] * (8 - $i);
        }
        $sum += $nums[8];

        return ($sum % 10 === 0);
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return '您輸入的身分證字號格式不正確。';
    }
}

有了這個規則後,在你的 Controller 或是 Form Request 中就可以像使用內建規則一樣呼叫它:

use App\Rules\TaiwanIdNumber;

$request->validate([
    'name' => 'required|string|max:255',
    'email' => 'required|email|unique:users',
    'tw_id' => ['required', 'string', new TaiwanIdNumber],
]);

我個人強烈建議,只要驗證邏輯稍微複雜,就應該使用 Form Request 來組織你的驗證邏輯,而不是全部塞在 Controller 裡,這對於大型專案的維護性來說,簡直是天壤之別。

第二道防線:Laravel Middleware – 你應用程式的忠實保鑣

如果說 Validation 是檢查訪客「攜帶的物品」(資料)是否合規,那 Middleware 就是檢查訪客「本身」的身份。他是個盡責的保鑣,在請求(Request)真正抵達你的 Controller 之前,對其進行層層過濾和檢查。

Middleware 到底是什麼?

你可以把 Middleware 想像成洋蔥的一層層外皮。一個 HTTP 請求進來,必須先通過全球 Middleware,再通過路由群組的 Middleware,最後通過單一路由的 Middleware,才能見到 Controller 本人。任何一層檢查不通過,請求就會被直接擋下並回傳錯誤,連 Controller 的門都摸不到。

常見的應用場景包括:

  • 權限驗證:使用者是否登入?是否為管理員?
  • API 金鑰驗證:請求是否攜帶了合法的 API Key?
  • 日誌記錄:記錄所有進入特定路由的請求。
  • 維護模式:在網站維護時,顯示特定的維護頁面。

打造你的客製化 Middleware

讓我們來實作一個常見的需求:檢查 API 請求的 Header 是否帶有有效的 `X-API-KEY`。首先,建立 Middleware:

php artisan make:middleware EnsureApiKeyIsValid

這會在 `app/Http/Middleware` 中建立 `EnsureApiKeyIsValid.php`。我們來修改 `handle` 方法:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class EnsureApiKeyIsValid
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // 從 .env 檔案中取得我們設定的有效 API Key
        $validApiKey = config('services.api.key');

        if (!$request->hasHeader('X-API-KEY') || $request->header('X-API-KEY') !== $validApiKey) {
            // 如果 Header 不存在或 Key 不正確,回傳 401 Unauthorized
            return response()->json(['message' => 'Unauthorized.'], 401);
        }

        // 驗證通過,將請求交給下一個 Middleware 或 Controller
        return $next($request);
    }
}

接著,我們必須註冊這個 Middleware。打開 `app/Http/Kernel.php`,在 `$routeMiddleware` 陣列中加入:

protected $routeMiddleware = [
    // ... 其他 middleware
    'api.key' => \App\Http\Middleware\EnsureApiKeyIsValid::class,
];

現在,你可以在你的 `routes/api.php` 檔案中,保護需要驗證金鑰的路由了:

Route::get('/protected-data', [DataController::class, 'index'])->middleware('api.key');

// 或是保護一整個路由群組
Route::middleware(['api.key'])->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
    Route::post('/settings', [SettingsController::class, 'update']);
});

這種方式遠比在每個 Controller 方法中都寫一次 API Key 驗證邏輯要來得優雅且容易維護。如果你需要更複雜的認證機制,例如 JWT,可以參考我們關於 Laravel JWT 深度實戰的文章,原理是相通的。

帶參數的 Middleware:打造更靈活的權限控管

有時候,我們希望 Middleware 能更靈活一點。例如,一個檢查使用者角色的 Middleware,我們希望可以動態傳入需要的角色名稱,而不是寫死一個 `IsAdmin`、一個 `IsEditor`…。

讓我們建立一個 `CheckRole` Middleware:

php artisan make:middleware CheckRole

修改 `handle` 方法,讓它可以接收額外的參數:

public function handle(Request $request, Closure $next, string $role)
{
    if (! $request->user() || ! $request->user()->hasRole($role)) {
        // 這裡的 hasRole 是一個假設你在 User Model 中實作的方法
        abort(403, 'Access Denied.');
    }

    return $next($request);
}

註冊後,你就可以這樣使用它:

Route::post('/posts', [PostController::class, 'store'])->middleware('role:editor');
Route::delete('/posts/{post}', [PostController::class, 'destroy'])->middleware('role:admin');

看到沒?一個 Middleware 就能處理多種角色的驗證,這就是客製化的威力!

總結:防線是疊加上去的,不是單點突破

寫到這裡,你應該能體會到,一個安全的 Laravel 應用程式,它的防線是立體的。Middleware 像是城牆與衛兵,負責阻擋不合法的身份;Validation 則是進城後的安檢,確保每個人攜帶的物品都安全無虞。兩者各司其職,缺一不可。

千萬不要再寫那種把所有邏輯都塞在 Controller 裡的「義大利麵」程式碼了。善用 Laravel 驗證與 Middleware 客製化 的強大功能,不僅能讓你的程式碼更清晰、更易於維護,更能為你的應用程式建立起一道道堅不可摧的防線。這是一個專業工程師的基本素養,也是對使用者資料負責的表現。

延伸閱讀

如果你對於如何將這些高階的開發技巧應用到你的 WordPress 網站,或是想打造更複雜的企業級系統感到好奇,甚至是遇到了難以解決的技術瓶頸,都歡迎與浪花科技的團隊聊聊。我們樂於分享我們的經驗,幫助你的專案提升到新的層次。

常見問題 (FAQ)

Q1: Laravel 的驗證 (Validation) 和中介層 (Middleware) 主要區別是什麼?

簡單來說,Validation 負責檢查「資料」的正確性與完整性,例如電子郵件格式是否正確、密碼長度是否足夠。而 Middleware 則負責過濾「請求」本身,處理的是身份驗證、權限控管等問題,它在請求到達你的主要邏輯之前就進行檢查。一個是安檢,一個是查驗身份。

Q2: 什麼時候該用客製化驗證規則 (Custom Rule),而不是在 Controller 用閉包 (Closure) 寫驗證?

當一個驗證邏輯很複雜,或者需要在多個地方重複使用時,就應該建立一個客製化的 Rule class。這遵循了 DRY (Don’t Repeat Yourself) 原則,讓你的程式碼更乾淨、可讀性更高,也更容易進行單元測試。如果只是一個非常簡單且只用一次的驗證,用閉包是可行的,但長遠來看,建立 Rule class 是更專業的做法。

Q3: 一個路由 (Route) 可以套用多個 Middleware 嗎?

絕對可以!你可以將多個 Middleware 的別名放在一個陣列中傳給 `middleware()` 方法,例如 `->middleware([‘auth’, ‘role:admin’])`。請求會依照陣列中的順序依序通過這些 Middleware,只要其中一個不通過,請求就會被中斷。順序非常重要,例如你必須先驗證登入 (`auth`),才能接著驗證角色 (`role`)。

Q4: 驗證邏輯的最佳實踐是放在哪裡?Controller 還是 Form Request?

對於非常簡單的驗證(一兩個欄位),放在 Controller 中使用 `$request->validate()` 是可以接受的。但只要驗證規則超過三四條,或是有複雜的條件式驗證,強烈建議使用 Form Request。它可以將驗證邏輯從 Controller 中抽離,讓 Controller 專注於處理商業邏輯,使程式碼結構更清晰,也更符合「單一職責原則」。

 
立即諮詢,索取免費1年網站保固