擋下髒資料:Laravel 11 Validation 與客製化 Middleware 實戰攻略
☰ 目錄 table-of-contents.md
後端最危險的假設,就是相信前端傳來的資料是乾淨的。表單驗證做在前端只是體驗,做在後端才是防線;Laravel 11 的 Validation 搭配客製化 Middleware,能在請求進入商業邏輯之前就把髒資料擋在門外。這篇從驗證規則寫到 Middleware 客製化,把這道防線實際建起來。
你是否曾經接手過這種專案:打開 Controller,迎面而來的是幾十行的 if-else 判斷?
- 「如果有
email欄位...」 - 「如果
password大於 6 個字...」 - 「如果這個使用者是管理員...」
這種寫法我稱之為「義大利麵防線」,看起來有在擋,但隨便戳一下就破了,而且維護起來簡直是地獄。在 Laravel 的世界裡,我們有兩把屠龍刀可以優雅地解決這個問題:驗證 (Validation) 與 中介層 (Middleware)。
特別是到了 2025 年,Laravel 11 在架構上做了不小的瘦身(移除了許多預設 config 檔案),很多原本寫在 Kernel.php 的設定現在都搬到了 bootstrap/app.php。這篇文章我將會用最新的 Laravel 11 觀念,帶你打造銅牆鐵壁般的 API。
為什麼你的 API 像是在「裸奔」?
很多初階工程師會覺得:「反正前端有做表單驗證了,後端隨便寫寫就好。」
大錯特錯!
前端驗證是用來「提升使用者體驗」的,不是用來「防駭客」的。任何人都可以透過 Postman 或 cURL 直接對你的 API 發送請求,繞過所有的前端驗證。如果你的 Laravel 後端沒有做好把關,惡意資料就會像喪屍一樣湧入你的資料庫。
Middleware vs. Validation:誰負責什麼?
在開始寫 Code 之前,我們要先釐清觀念,這也是很多面試會考的題目:
- Middleware (中介層): 像是大樓的保全。他不管你包包裡裝什麼,他只看你有沒有識別證 (Token)、是不是被列入黑名單 (IP Ban)、或是現在是不是開放時間 (Rate Limiting)。
- Validation (驗證): 像是櫃檯的行政人員。保全放你進來後,行政人員會檢查你的申請表 (Request Data) 有沒有填寫正確、Email 格式對不對、商品庫存夠不夠。
第一道防線:客製化 Middleware (Laravel 11 新制)
假設我們有一個需求:只有來自特定合作夥伴 API Key 的請求才能存取我們的特定路由。
首先,我們建立一個 Middleware:
php artisan make:middleware CheckPartnerApiKey
接著,打開產生的 app/Http/Middleware/CheckPartnerApiKey.php。我們要檢查 Header 裡是否有正確的 Key。
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CheckPartnerApiKey
{
/**
* Handle an incoming request.
*/
public function handle(Request $request, Closure $next): Response
{
$validApiKey = config('services.partner.api_key'); // 建議將 Key 放在 .env 並透過 config 讀取
$requestApiKey = $request->header('X-Partner-Key');
if ($requestApiKey !== $validApiKey) {
return response()->json([
'status' => 'error',
'message' => 'Unauthorized: Invalid API Key',
], 401);
}
return $next($request);
}
}
Laravel 11 的註冊方式變革
在 Laravel 10 以前,我們會去 app/Http/Kernel.php 註冊。但在 Laravel 11,Kernel.php 已經消失了!現在我們要在 bootstrap/app.php 進行設定,這是一個更簡潔的現代化做法。
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use App\Http\Middleware\CheckPartnerApiKey;
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([
'partner.auth' => CheckPartnerApiKey::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
現在,你就可以在 routes/api.php 中輕鬆使用了:
Route::middleware(['partner.auth'])->group(function () {
Route::post('/partner/sync', [PartnerController::class, 'syncData']);
});
第二道防線:Form Request Validation (表單請求驗證)
Middleware 擋掉了閒雜人等,接下來要處理資料正確性。請絕對不要在 Controller 裡面寫 $request->validate([...]),那會讓你的 Controller 變得非常肥大且難以閱讀。請使用 Form Request。
假設我們要建立一個「新增產品」的 API。
php artisan make:request StoreProductRequest
打開 app/Http/Requests/StoreProductRequest.php,這裡有兩個核心方法:authorize() 和 rules()。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreProductRequest extends FormRequest
{
/**
* 判斷使用者是否有權限執行此請求
*/
public function authorize(): bool
{
// 這裡可以整合 Policy,例如:
// return $this->user()->can('create', Product::class);
return true;
}
/**
* 定義驗證規則
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'sku' => ['required', 'string', 'unique:products,sku'], // 檢查資料庫唯一性
'price' => ['required', 'numeric', 'min:0'],
'categories' => ['required', 'array', 'min:1'],
'categories.*' => ['exists:categories,id'], // 檢查陣列中的每個 ID 是否存在於資料庫
'is_active' => ['boolean'],
];
}
/**
* 自訂錯誤訊息 (可選,適合多語系或更友善的提示)
*/
public function messages(): array
{
return [
'sku.unique' => '這組 SKU 已經有人用過了,請換一組吧!',
'categories.*.exists' => '您選取的分類不存在,請重新整理頁面。',
];
}
}
在 Controller 中使用
這就是最迷人的地方。當你將 Type Hint 指定為你剛剛建立的 StoreProductRequest 時,Laravel 會自動在進入 Controller 方法之前執行驗證。如果驗證失敗,它會自動回傳 JSON 格式的 422 錯誤訊息,Controller 的程式碼一行都不會被執行!
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreProductRequest;
use App\Models\Product;
use Illuminate\Http\JsonResponse;
class ProductController extends Controller
{
public function store(StoreProductRequest $request): JsonResponse
{
// 能進到這裡,代表資料絕對是乾淨、正確的
// 不需要再寫任何 if-else 檢查欄位
// 直接取用驗證過的資料
$validated = $request->validated();
$product = Product::create($validated);
return response()->json($product, 201);
}
}
看,你的 Controller 是不是清爽到想哭?這就是「關注點分離 (Separation of Concerns)」的藝術。
進階技巧:自訂驗證規則 (Custom Rules)
有時候,Laravel 內建的規則不夠用。例如,你的電商系統規定:「如果是預購商品 (Pre-order),出貨日期必須在 30 天以後」。這時候就需要自訂規則。
php artisan make:rule PreOrderDateCheck
編寫邏輯:
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Carbon\Carbon;
class PreOrderDateCheck implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
// 假設 request 中有另一個欄位叫 type
if (request()->input('type') === 'pre_order') {
$date = Carbon::parse($value);
if ($date->diffInDays(now()) < 30) {
$fail('預購商品的 :attribute 必須設定在 30 天之後。');
}
}
}
}
然後在 Form Request 中使用:
use App\Rules\PreOrderDateCheck;
// ... inside rules array
'shipping_date' => ['required', 'date', new PreOrderDateCheck],
結論:寫出優雅的 Code,晚上睡得比較好
作為一名資深工程師,我深信「防禦性程式設計 (Defensive Programming)」的核心不在於你寫了多少複雜的邏輯,而在於你如何利用框架提供的工具,把不乾淨的資料擋在門外。
利用 Laravel 11 的 Middleware 來管理存取權限,利用 Form Request 來確保資料完整性,你的應用程式將會變得像一座堅固的城堡。駭客進不來,髒資料進不來,你的 Controller 就能專心地處理商業邏輯,而不是在那邊當清潔工。
推薦閱讀
如果你對 Laravel 的架構安全與資料處理有興趣,強烈建議你延伸閱讀以下幾篇我精選的文章,這能讓你的技術視野更上一層樓:
- API 金鑰之亂終結者:Laravel + JWT 深度實戰,打造無狀態認證的現代化後端!
- 肥 Controller 瘦不下來?Laravel 後台架構終極對決:Repository vs. Service vs. Action 模式
- 不只是單向拋接!Laravel x HubSpot 進階戰術:打造企業級雙向、容錯、高效率的資料流引擎
如果你發現你的 Laravel 專案已經變成一團難以維護的義大利麵,或者你需要企業級的 API 架構規劃,別猶豫,讓我們來幫你重構出藝術品般的程式碼。
需要專業的 Laravel 架構諮詢嗎?
浪花科技擁有豐富的 Laravel 企業級開發經驗,從高流量 API 到複雜的 SaaS 系統,我們都能提供最穩健的解決方案。別讓技術債拖垮你的業務成長!
立即填寫表單聯繫 Eric 與技術團隊常見問題
Laravel 的 Middleware 和 Validation 有什麼差別?
前端已經做了表單驗證,後端還需要驗證嗎?
Laravel 11 的 Middleware 註冊方式和舊版有什麼不同?
為什麼建議用 Form Request 而不是在 Controller 裡寫驗證?
訂閱免費電子報
把 AI 自動化、企業系統設計與 WordPress / Laravel 開發的真實案例和可直接照做的技巧,整理成電子報寄給你。只寄精選內容、不灌垃圾信,一鍵就能退訂。