Laravel 防線告急?手刻驗證 (Validation) 與中介層 (Middleware),打造駭客也繞道的銅牆鐵壁!

2025/12/27 | Laravel技術分享, 全端與程式開發

Laravel 應用程式防線:手刻驗證與中介層的終極實戰

「別再讓您的 Laravel API 裸奔了!」許多開發者誤以為內建驗證即是萬靈丹,但真正的企業級安全需要銅牆鐵壁。本文揭示客製化驗證規則與中介層的應用精髓。我們透過 Rule Object 完美封裝複雜的商業邏輯(如優惠券有效性),並透過 Middleware 打造 API 金鑰驗證的堅實守門人,將非法請求拒之門外。現在是時候跳脫基礎教學,將您的應用程式架構成駭客無法繞道的防線。如果您需要打造穩固、可擴展的系統架構,立即聯繫浪花科技,讓我們一起為您的下一個偉大產品穿上最堅實的盔甲!

需要專業協助?

聯絡浪花專案團隊 →

Laravel 防線告急?手刻驗證 (Validation) 與中介層 (Middleware),打造駭客也繞道的銅牆鐵壁!

嗨,我是浪花科技的 Eric。身為一個天天在 Code 海裡打滾的工程師,我看過太多 Laravel 新手把專案當作一個開放式樂園,大門敞開,誰都能進來玩。他們可能會說:「我有用 Laravel 內建的 validation 啊!'email' => 'required|email',很安全吧?」

每次聽到這個,我工程師的小囉嗦模式就會自動開啟。兄弟,這就像是你家大門裝了個喇叭鎖,就自以為固若金湯了。真正的戰場上,你需要的是護城河、是瞭望塔,是層層把關的鐵衛。在 Laravel 的世界裡,這對無敵的守衛組合,就是「客製化驗證 (Custom Validation)」與「客製化中介層 (Custom Middleware)」。

今天,就讓我帶你跳脫官方文件的基礎教學,深入這兩個 Laravel 核心功能的精髓,從 0 到 1 打造出真正企業級、讓駭客看到都想繞道的應用程式防線。

第一道防線:客製化驗證規則 (Custom Validation Rules) — 不只驗證格式,更要驗證商業邏輯

Laravel 內建的驗證規則(required, email, max, min…)非常方便,處理常規的表單綽綽有餘。但當你的業務邏輯開始變得複雜時,它們就顯得捉襟見肘了。這時候,就是客製化驗證規則登場的最佳時機。

什麼時候該手刻驗證規則?

當你的驗證邏輯符合以下任一情境時,別懷疑,就是它了:

  • 複雜的格式驗證:例如台灣的身分證字號、手機條碼、公司統一編號,這些都有固定的演算法,不是一個簡單的正規表達式就能搞定的。
  • 需查詢資料庫的驗證:例如,驗證使用者輸入的優惠券代碼是否存在、是否已過期、是否已被使用。
  • 跨欄位的相依性驗證:例如,當「運送方式」選擇「宅配」時,「運送地址」欄位才變成必填。
  • 可重用的商業邏輯:如果某個驗證邏輯會在多個地方被使用(例如,A 表單和 B API 都需要驗證同一個東西),把它封裝成一個獨立的 Rule Object 是最乾淨的做法。

實戰演練:打造一個「優惠券驗證」規則

想像一下,我們正在開發一個電商網站,需要一個驗證 Coupon Code 的規則。這個規則需要檢查三件事:1. Code 存在於資料庫 2. 尚未過期 3. 未被使用。光用內建規則肯定做不到。來,打開你的終端機,跟著我一起做:

步驟一:建立 Rule 物件

Artisan 指令是我們最好的朋友,一行指令就能建立好我們的規則檔案結構:

php artisan make:rule IsValidCoupon

這會在 app/Rules 資料夾下建立一個 IsValidCoupon.php 檔案。

步驟二:撰寫驗證邏輯

打開 IsValidCoupon.php,你會看到兩個主要的方法:passes()message()。這就是我們的主戰場。

  • passes($attribute, $value):這是驗證的核心。$value 就是使用者傳入的值(我們的 coupon code)。這個方法必須回傳 true(驗證通過)或 false(驗證失敗)。
  • message():當驗證失敗時,要回傳給使用者的錯誤訊息。

讓我們把商業邏輯寫進去:

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use App\Models\Coupon; // 假設你有一個 Coupon 的 Eloquent Model
use Carbon\Carbon;

class IsValidCoupon implements Rule
{
    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        // 1. 檢查優惠券是否存在
        $coupon = Coupon::where('code', $value)->first();

        if (!$coupon) {
            return false;
        }

        // 2. 檢查是否已被使用 (假設 used_at 欄位為 null 代表尚未使用)
        if ($coupon->used_at !== null) {
            return false;
        }

        // 3. 檢查是否已過期 (假設 expires_at 是到期日)
        if (Carbon::now()->gt($coupon->expires_at)) {
            return false;
        }

        // 所有檢查都通過了!
        return true;
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        // 給使用者一個通用的、安全的錯誤訊息
        return '您輸入的優惠券代碼無效或已過期。';
    }
}

步驟三:在控制器或 Form Request 中使用

現在,我們可以在需要的地方優雅地使用這個規則了。我強烈建議使用 Form Request 來組織你的驗證邏輯,這能讓你的 Controller 保持乾淨。這才是資深工程師的作法,別把所有邏輯都塞在 Controller 裡,那會變成一場災難!

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Rules\IsValidCoupon; // 記得引入我們的規則

class ApplyCouponRequest extends FormRequest
{
    public function rules()
    {
        return [
            'coupon_code' => ['required', 'string', new IsValidCoupon()],
            // 其他欄位...
        ];
    }
}

看到了嗎?new IsValidCoupon(),就是這麼簡潔。我們把複雜的商業邏輯完美地封裝起來,控制器只需要專注於處理驗證通過後的請求即可。這不僅提高了程式碼的可讀性,也讓這個規則可以在任何地方被重複使用。

第二道防線:客製化中介層 (Custom Middleware) — API 的忠實守門人

如果說 Validation 是檢查「信件內容」是否合規的審查員,那 Middleware 就是在信件送達前,檢查「信封」和「郵差身份」的守衛。它在請求生命週期的最前端,可以決定一個請求是否有資格繼續往下走。

什麼時候該手刻 Middleware?

  • API 金鑰驗證:所有需要保護的 API 都應該有一個 Middleware 來檢查請求 Header 中的 API Key 是否有效。
  • 權限控管:檢查登入的使用者是否具有特定角色(例如:管理員、編輯)才能存取某個路由。
  • 請求日誌 (Logging):記錄所有傳入的 API 請求,方便追蹤與除錯。
  • 維護模式:在特定條件下,將網站導向維護頁面。
  • 修改請求或回應:在請求送達控制器前,可以先加上特定的 Header;或在回應送回給使用者前,統一加上某些 Header。

實戰演練:打造一個「API 金鑰驗證」中介層

假設我們的 App 需要提供一組 API 給合作夥伴使用,我們得確保只有合法的請求才能存取。最常見的做法就是透過 HTTP Header 中的 `X-API-KEY` 來驗證。

步驟一:建立 Middleware

php artisan make:middleware EnsureApiKeyIsValid

這會在 app/Http/Middleware 資料夾下建立一個 EnsureApiKeyIsValid.php 檔案。

步驟二:撰寫處理邏輯

打開檔案,核心就在 handle() 方法。這個方法有兩個重要的參數:$request$next

  • $request:就是傳入的 HTTP 請求物件,我們可以從中取得 Header、輸入等資訊。
  • $next:這是一個 Closure(閉包)。如果驗證通過,你必須呼叫 $next($request),把請求「交棒」給下一個處理程序(可能是另一個 Middleware,或最終的控制器)。如果沒有呼叫它,請求就會在這裡被中止。
<?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');

        // 從請求的 Header 中取得傳入的 API Key
        $submittedApiKey = $request->header('X-API-KEY');

        // 進行比對
        if (!$submittedApiKey || $submittedApiKey !== $validApiKey) {
            // 如果驗證失敗,直接回傳 401 Unauthorized 錯誤,中斷請求
            return response()->json(['message' => 'Unauthorized.'], 401);
        }

        // 驗證通過!交給下一個程序處理
        return $next($request);
    }
}

一個小提醒:千萬不要把 API Key 這種敏感資訊直接寫在程式碼裡,務必放在 .env 檔案中,然後透過 config() 輔助函數來讀取。

步驟三:註冊並使用 Middleware

Middleware 寫好了,但 Laravel 還不知道它的存在。我們需要去註冊它。在 Laravel 11 中,這件事變得更簡潔了,直接在 bootstrap/app.php 檔案中操作:

->withMiddleware(function (Middleware $middleware) {
    // 給我們的 middleware 一個好記的別名
    $middleware->alias([
        'api.key' => \App\Http\Middleware\EnsureApiKeyIsValid::class,
    ]);
})

註冊完畢後,就可以在路由檔案(例如 routes/api.php)中保護我們的 API 了:

use App\Http\Controllers\PartnerController;

// 方法一:保護單一路由
Route::get('/partner/data', [PartnerController::class, 'getData'])->middleware('api.key');

// 方法二:保護一整個路由群組 (更推薦的作法)
Route::middleware(['api.key'])->prefix('partner')->group(function () {
    Route::get('/data', [PartnerController::class, 'getData']);
    Route::post('/update', [PartnerController::class, 'updateData']);
});

搞定!現在所有在那個群組內的 API,都必須在 Header 帶上正確的 `X-API-KEY` 才能存取。這道防線,堅固!

總結:打造可信賴的應用程式,從細節做起

身為工程師,我們寫的 Code 不只是要「能動」,更要「可靠」、「安全」、「可維護」。Laravel 驗證與 Middleware 客製化,正是實踐這些原則的關鍵武器。

客製化驗證讓我們能將複雜的商業規則封裝起來,保持 Controller 的簡潔;客製化中介層則為我們的應用程式建立了一道又一道的安檢門,將非法請求拒之門外。當你熟練地運用這兩者時,你就不再只是一個「會用框架」的開發者,而是一個真正懂得如何「架構應用程式」的工程師。

這條路很長,但每一步都值得。別再讓你的 Laravel API 裸奔了,現在就動手,為它穿上最堅實的盔甲吧!

延伸閱讀

如果你在打造 Laravel 應用程式時遇到了更複雜的架構問題,或是需要企業級的 API 安全解決方案,別客氣,浪花科技的團隊隨時準備好為你提供專業的技術支援。我們不只會寫 Code,更擅長打造穩固、可擴展的系統架構。
立即聯繫我們,讓我們一起打造下一個偉大的產品!

常見問題 (FAQ)

Q1: 客製化驗證規則 (Rule Object) 跟直接在 Validator 使用閉包 (Closure) 有什麼主要差別?

A1: 閉包適合用在單一、不會重複使用的簡單驗證邏輯上,寫起來快速方便。但如果你的驗證邏輯比較複雜,或是在系統中多個地方都會用到(例如,不同表單或 API 都需要驗證同一個東西),那麼建立一個獨立的 Rule Object 是更好的選擇。Rule Object 讓你的驗證邏輯可以被重複使用、更容易進行單元測試,也讓你的 Form Request 或 Controller 程式碼更乾淨、語意更清晰。

Q2: 什麼時候我應該用 Middleware,而不是直接把邏輯寫在 Controller 的方法裡?

A2: 這是一個很棒的架構問題!你應該使用 Middleware 的時機是當一個「檢查」或「動作」需要在「多個路由」上執行,或是在 Controller 核心業務邏輯「之前」就必須完成。例如:身份驗證、API 金鑰檢查、權限控管、請求日誌記錄等。把這些共通的邏輯抽離到 Middleware,可以避免在每個 Controller 方法中重複撰寫相同的程式碼,完全符合 DRY (Don’t Repeat Yourself) 原則,讓你的 Controller 更專注於處理單一的業務需求。

Q3: 我用的還是舊版的 Laravel,註冊 Middleware 的方式有什麼不同嗎?

A3: 是的,在 Laravel 11 之前,Middleware 的註冊主要是在 app/Http/Kernel.php 這個檔案中進行。你會在該檔案中看到 $middleware(全域)、$middlewareGroups(群組,如 ‘web’ 和 ‘api’)以及 $routeMiddleware(路由別名)這三個屬性。你需要將你的客製化 Middleware class 加入到 $routeMiddleware 陣列中並給予一個別名,用法和新版大同小異。Laravel 11 將這些設定統一集中到 bootstrap/app.php,讓設定更集中化。

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