駭客絕望!Laravel 11 打造 API 銅牆鐵壁的雙重門神
後端工程師常因「偷懶」忽略資料驗證,導致系統暴露於致命風險。本文以 Laravel 11 為核心,教您如何運用 Form Request 告別混亂的 Controller,實踐關注點分離;並透過客製化 Middleware 迎戰 Laravel 11 新架構,建立 API 的第一道警衛室。我們將深入探討 Middleware 與 Validation 的雙重防線,徹底杜絕髒資料與未授權存取。別再讓您的 API 裸奔!立即升級系統防護,聯繫浪花科技,由資深工程師為您終結技術債。
你的 API 像公共廁所隨便進?Laravel 11 驗證 (Validation) 與 Middleware 客製化終極實戰,打造駭客絕望的銅牆鐵壁
嘿,我是 Eric,浪花科技的資深工程師。今天我們要來聊聊後端工程師最容易「偷懶」,但也是最致命的環節:資料驗證 (Validation) 與 中介層 (Middleware)。
在 Code Review 的時候,我最常對 Junior 工程師說的一句話就是:「永遠不要相信前端傳來的資料,就算那個前端是你自己寫的也一樣。」很多新手會覺得,反正前端表單已經有擋必填了,後端直接存進資料庫就好啦?錯!大錯特錯!這就像是你家大門沒鎖,只掛了一個「請勿進入」的牌子一樣,駭客(或者只是調皮的使用者)只要用 Postman 或 cURL 繞過前端,就能把你的資料庫變成垃圾場,甚至發動 SQL Injection 攻擊。
在這篇文章中,我將以 Laravel 11 為基礎(沒錯,我們要跟上最新版本,別再抱著 Kernel.php 不放了),帶你深入探討如何透過 Laravel 驗證與 Middleware 客製化,打造出滴水不漏的 API 防護網。我們會從 Form Request 的優雅寫法,一路講到 Laravel 11 最新的 Middleware 註冊方式。
為什麼我們需要「雙重驗證」機制?
在討論技術細節前,我們要先建立正確的觀念。一個健壯的後端架構,通常會有兩道門神:
- 第一道防線:Middleware (中介層)
這是 API 的「警衛室」。它不負責檢查你帶了什麼行李(資料),而是檢查「你是誰」以及「你有沒有資格進來」。例如:身份驗證 (Auth)、權限檢查 (RBAC)、頻率限制 (Rate Limiting) 以及 CORS 設定。 - 第二道防線:Validation (驗證邏輯)
這是 API 的「安檢門」。當你通過警衛室後,我們要打開你的行李,檢查裡面的資料是否符合規定。例如:Email 格式對不對?密碼強度夠不夠?這個 Coupon Code 是否存在?
如果這兩層沒做好,你的 Controller 就會充滿了髒 code,既難維護又充滿漏洞。接下來,我們就來實戰操作。
Laravel 驗證 (Validation) 進階實戰:拒絕髒資料
1. 告別 Controller 裡的 $request->validate()
很多教學會教你在 Controller 裡直接寫驗證邏輯:
// ❌ 這種寫法是這維護惡夢的開始
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|max:255',
'body' => 'required',
]);
// 業務邏輯...
}
雖然這樣寫很快,但當規則一多,你的 Controller 就會變得像一坨義大利麵。身為資深工程師,我們追求的是「關注點分離 (Separation of Concerns)」。請愛用 Form Request。
在終端機輸入:
php artisan make:request StorePostRequest
這會在 app/Http/Requests 產生一個檔案。我們可以在這裡定義規則:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
// 這裡可以做簡單的權限判斷,例如只有管理員能發文
return true;
}
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:255'],
'slug' => ['required', 'string', 'unique:posts,slug'],
'status' => ['required', 'in:draft,published,archived'],
'author_id' => ['required', 'exists:users,id'], // 確保關聯資料存在
];
}
// 自訂錯誤訊息,讓前端工程師感謝你
public function messages(): array
{
return [
'slug.unique' => '這個網址代稱已經被用過了,換一個吧!',
'author_id.exists' => '找不到這位作者,請確認 ID 是否正確。',
];
}
}
然後,在你的 Controller 只需要這樣寫:
public function store(StorePostRequest $request)
{
// 程式執行到這裡時,保證資料已經驗證通過並經過過濾
// 你的 Controller 瞬間清爽了 50%!
$data = $request->validated();
Post::create($data);
return response()->json(['message' => '發布成功']);
}
2. 進階技巧:自訂驗證規則 (Custom Rules)
有些時候,Laravel 內建的規則不夠用。例如,你需要驗證一個「台灣手機號碼」格式(09開頭,共10碼)。這時候別在 Controller 寫 regex,請建立一個 Rule:
php artisan make:rule TaiwanPhoneNumber
在 Laravel 11 中,預設是產生 Invokable Rule,寫法非常簡潔:
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class TaiwanPhoneNumber implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (!preg_match('/^09\d{8}$/', $value)) {
$fail("The :attribute must be a valid Taiwan phone number.");
}
}
}
使用方式:
use App\Rules\TaiwanPhoneNumber;
// 在 Form Request 中
'phone' => ['required', new TaiwanPhoneNumber],
Middleware 客製化:Laravel 11 的變革
來到 Middleware 客製化 的部分。如果你是從舊版本升級上來的,這部分要注意了。Laravel 11 移除了 app/Http/Kernel.php,Middleware 的註冊方式改到了 bootstrap/app.php。
假設我們要寫一個 Middleware,用來檢查 Request Header 是否包含特定的 API Key(這在跟第三方廠商串接時很常見)。
1. 建立 Middleware
php artisan make:middleware CheckApiKey
編輯 app/Http/Middleware/CheckApiKey.php:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CheckApiKey
{
public function handle(Request $request, Closure $next): Response
{
// 檢查 Header 中的 X-API-KEY
$apiKey = $request->header('X-API-KEY');
if ($apiKey !== env('MY_SECRET_API_KEY')) {
// 如果不符,直接退貨,連 Controller 都不讓他進
return response()->json(['error' => 'Unauthorized: Invalid API Key'], 401);
}
return $next($request);
}
}
2. 在 Laravel 11 中註冊 Middleware
現在,打開 bootstrap/app.php,這是新的控制中心:
use App\Http\Middleware\CheckApiKey;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
// 註冊別名 (Alias),方便在 Route 中使用
$middleware->alias([
'api.key' => CheckApiKey::class,
]);
// 或者,如果你想要全域套用 (Global Middleware)
// $middleware->append(CheckApiKey::class);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
3. 在 Route 中使用
註冊完別名後,就可以在 routes/api.php 輕鬆掛上去了:
Route::middleware(['api.key'])->group(function () {
Route::post('/secure-data', [SecureController::class, 'store']);
});
Eric 的開發小叮嚀 (Best Practices)
結合了 Laravel 驗證與 Middleware 客製化,你的 API 安全性已經贏過 80% 的網站了。但身為過來人,Eric 還有幾點要囉嗦一下:
- 不要依賴前端驗證: 前端驗證只是為了提升使用者體驗 (UX),讓使用者不用等到送出表單才知道填錯了。後端驗證才是真正的守門員。
- 善用
prepareForValidation: 在 Form Request 中,你可以使用prepareForValidation方法來先處理資料。例如把email轉小寫,或是把全形數字轉半形,再進行驗證,這能大幅減少資料髒亂的機會。 - 回傳統一的錯誤格式: 當 Middleware 攔截或 Validation 失敗時,確保回傳的 JSON 結構是一致的。不要一下回傳
{"error": "msg"},一下回傳{"message": "msg"},前端工程師會想拿鍵盤丟你。
相關閱讀
想要打造更完美的 Laravel 系統?這裡有三篇我精選的進階文章,強烈建議延伸閱讀:
- API 金鑰之亂終結者:Laravel + JWT 深度實戰,打造無狀態認證的現代化後端! – 學會了驗證資料,下一步就是學會驗證「人」。JWT 是 API 開發的必備技能。
- 拒絕髒資料進門!Laravel 11 終極驗證 (Validation) 與客製化中介層 (Middleware) 實戰攻略 – 本文的深度延伸與基礎觀念補強。
- 告別雜亂無章!資深工程師帶你走進 Laravel Admin 後台架構設計的藝術 – 好的驗證與 Middleware 只是架構的一部分,看看如何設計整個後台系統。
如果你發現公司的 API 像是一團混亂的毛線球,或者每次修改驗證邏輯都要改動五六個檔案,那代表你們的系統架構需要「進廠維修」了。
浪花科技 專注於高強度的 Laravel 系統開發與 WordPress 客製化。我們不只寫 Code,更在乎系統的可維護性與安全性。如果你有任何技術債需要處理,或者想打造企業級的 Web 應用,歡迎聯繫我們。
常見問題 (FAQ)
Q1: Laravel 11 的 Middleware 寫法跟舊版有什麼最大的不同?
最大的不同在於註冊位置。Laravel 11 移除了 app/Http/Kernel.php,改為在 bootstrap/app.php 中使用 ->withMiddleware() 方法來註冊全域 Middleware 或別名 (Alias)。這讓專案結構更簡潔,但也需要適應新的配置方式。
Q2: 為什麼建議使用 Form Request 而不是在 Controller 裡驗證?
使用 Form Request 符合「單一職責原則 (SRP)」。Controller 應該專注於處理請求的流程與回應,而不該被大量的驗證規則佔據。Form Request 讓驗證邏輯可被重複利用,且支援 authorize 權限檢查與自訂錯誤訊息,能讓程式碼更乾淨、易讀且好維護。
Q3: 如果驗證失敗,Laravel 預設會發生什麼事?
如果是 API 請求(Header 帶有 Accept: application/json),Laravel 會自動捕捉 ValidationException 並回傳 HTTP 422 Unprocessable Entity 狀態碼,以及包含錯誤欄位訊息的 JSON。這也是為什麼我們不需要手動寫 try-catch 來處理驗證錯誤,Laravel 已經幫我們處理好了。






