API 像公共廁所隨便進?Laravel 11 JWT 終極實戰:打造駭客絕望的無狀態驗證堡壘

2026/01/17 | API 串接與自動化, Laravel技術分享, 全端與程式開發, 網站安全與防護

打造 Laravel 11 銅牆鐵壁:JWT 無狀態驗證實戰

您的 API 登入機制還在依賴傳統且低效的 Session 與 Cookie 嗎?資深工程師 Eric 警告,有狀態驗證是跨域地獄和擴展性的殺手!本文將帶您進入 2025 年業界標準:JWT(JSON Web Token)。我們將以最新的 Laravel 11 為基礎,透過實戰步驟部署 `jwt-auth`,從 Model 改造到 Auth Guard 設定,建立一個高效、易於擴展的無狀態驗證堡壘。別再讓您的後門洞開!立即行動,強化您的 API 防線。如果想確保系統具備最高的資安標準與 Refresh Token 輪替機制,立即聯繫浪花科技,為您的專案打造堅不可摧的後端架構!

需要專業協助?

聯絡浪花專案團隊 →

API 像公共廁所隨便進?Laravel 11 JWT 終極實戰:打造駭客絕望的無狀態驗證堡壘

大家好,我是浪花科技的資深工程師 Eric。今天我們不聊那些虛無縹緲的理論,直接來談談你的 API 後門。

我常在 Code Review 時看到新手工程師(有時候甚至是資深老鳥)在開發前後端分離的系統時,還在試圖用 Session 和 Cookie 來處理 API 的登入狀態。兄弟,醒醒吧!當你的前端是 Vue、React,甚至是 iOS 或 Android App 時,Session 那套依賴瀏覽器的機制只會讓你陷入 CORS (跨來源資源共用) 的無限地獄,而且伺服器還得記住每個人的 Session ID,流量一大,Redis 或 Memcached 直接爆給你看。

在 2025 年的現在,JWT (JSON Web Token) 幾乎是 RESTful API 驗證的業界標準。今天這篇文章,Eric 要帶大家在最新的 Laravel 11 環境下,從零打造一個銅牆鐵壁般的「無狀態 (Stateless)」驗證系統。我們不只要「能動」,還要「安全」。

為什麼你的 API 需要 JWT?(Session 到底錯在哪?)

簡單來說,傳統的 Session 是「有狀態 (Stateful)」的。伺服器必須在記憶體或資料庫中記住「誰登入了」。

  • 擴展性差: 如果你有 10 台伺服器做負載平衡,你還得搞 Session 共享,架構瞬間變複雜。
  • 跨域問題: 前端網域跟後端不同,Cookie 傳遞困難重重。
  • 行動裝置不友善: 原生 App 處理 Cookie 遠比處理 Header 裡的 Token 麻煩。

而 JWT 是「無狀態 (Stateless)」的。伺服器不需要記住任何東西。Token 本身就包含了使用者的身份資訊(Payload)和一個防止被篡改的簽名(Signature)。前端把 Token 放在 Header 裡丟過來,Laravel 只要拿密鑰驗證簽名是對的,就放行。這才是現代 API 該有的樣子。

實戰開始:Laravel 11 + JWT Auth

在 Laravel 生態系中,雖然官方有 Passport 和 Sanctum,但如果你想要最純粹、完全掌控的 JWT 實作,php-open-source-saver/jwt-auth(原 tymon/jwt-auth 的維護分支)依然是首選。

步驟 1:安裝套件

打開你的終端機,別手軟,指令敲下去:

composer require php-open-source-saver/jwt-auth

步驟 2:發布設定檔與生成密鑰

安裝完後,我們需要把設定檔拉出來,並且生成一個用來加密的 Secret Key。這個 Key 就是你的命根子,絕對不能外洩。

php artisan vendor:publish --provider="PHPOpenSourceSaver\JWTAuth\Providers\LaravelServiceProvider"
php artisan jwt:secret

執行後,你會在 .env 檔裡看到一行 JWT_SECRET=xxxxx。如果這一行洩漏了,駭客就能偽造任何人的 Token 登入你的系統,切記保護好它。

步驟 3:改造 User Model

接下來,我們要讓 Laravel 的 User 模型支援 JWT。打開 app/Models/User.php,我們需要實作 JWTSubject 介面。

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject; // 記得引入這個

class User extends Authenticatable implements JWTSubject
{
    // ... 其他原有的程式碼 ...

    /**
     * 取得會儲存在 JWT Subject Claim 的識別值 (通常是 user id)
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * 返回一個鍵值陣列,包含要加入到 JWT payload 中的自訂聲明
     */
    public function getJWTCustomClaims()
    {
        return []; // 可以在這裡加入 role, email 等非敏感資訊
    }
}

Eric 的小囉嗦:在 getJWTCustomClaims 裡,千萬不要放密碼、身分證字號這種敏感個資!因為 JWT 的 Payload 只是 Base64 編碼,是可以被輕易解碼看到的。這裡頂多放個 role_idusername 就好。

步驟 4:設定 Auth Guard

打開 config/auth.php,我們要告訴 Laravel,針對 API 的驗證,我們要改用 JWT 驅動。

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'jwt', // 這裡改成 jwt
        'provider' => 'users',
    ],
],

步驟 5:打造 AuthController

重頭戲來了,我們來寫一個處理登入、登出、取得個人資料的控制器。在終端機輸入 php artisan make:controller AuthController

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;

class AuthController extends Controller
{
    /**
     * 建構子,設定 middleware
     */
    public function __construct()
    {
        // 除了 login 以外,其他方法都需要驗證
        $this->middleware('auth:api', ['except' => ['login']]);
    }

    /**
     * 登入並取得 Token
     */
    public function login()
    {
        $credentials = request(['email', 'password']);

        if (! $token = auth('api')->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);
    }

    /**
     * 取得當前登入使用者的資料
     */
    public function me()
    {
        return response()->json(auth('api')->user());
    }

    /**
     * 登出 (讓 Token 失效)
     */
    public function logout()
    {
        auth('api')->logout();

        return response()->json(['message' => 'Successfully logged out']);
    }

    /**
     * 刷新 Token (換取新 Token)
     */
    public function refresh()
    {
        return $this->respondWithToken(auth('api')->refresh());
    }

    /**
     * 統一回傳 Token 的格式
     */
    protected function respondWithToken($token)
    {
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth('api')->factory()->getTTL() * 60 // 預設單位是分鐘,換算成秒
        ]);
    }
}

步驟 6:設定 API 路由

最後一步,到 routes/api.php 把路徑接通。

use App\Http\Controllers\AuthController;

Route::group(['middleware' => 'api', 'prefix' => 'auth'], function ($router) {
    Route::post('login', [AuthController::class, 'login']);
    Route::post('logout', [AuthController::class, 'logout']);
    Route::post('refresh', [AuthController::class, 'refresh']);
    Route::post('me', [AuthController::class, 'me']);
});

資安加固:Eric 的經驗談

做到上面那樣,你的 API 已經可以運作了,但在資深工程師眼裡,這只是個半成品。以下幾點是你必須注意的:

  • HTTPS 是標配: 不要以為用了 Token 就可以不用 SSL。如果沒有 HTTPS,Token 在網路上裸奔,一樣會被攔截竊取。
  • Token 時效性 (TTL): 預設 Token 有效期可能是一小時 (60分鐘)。別設太長(例如一年),否則 Token 被盜用造成的風險極大。通常建議 Access Token 設短一點(例如 15-60 分鐘),搭配 Refresh Token 機制來延長使用時間。
  • 黑名單機制: JWT 最大的缺點是一旦發出去,在過期前都有效。Laravel 的 JWT 套件有實作「黑名單 (Blacklist)」功能。當使用者登出時,其實是把該 Token 加入黑名單,讓它提早失效。請確保你的 Cache Driver (如 Redis) 有設定好,以保持高效能。

結語

API 的驗證機制是整個系統安全的第一道防線,使用 Laravel 11 搭配 JWT,可以讓你輕鬆構建出高效、安全且易於擴展的後端服務。別再留戀 Session 了,勇敢地擁抱無狀態架構吧!

如果在實作過程中遇到任何怪問題,或是對於 Refresh Token 的輪替機制感到頭痛,歡迎隨時來找我們。

延伸閱讀

你的 Laravel API 安全性足夠嗎?或是需要建置高併發的後端架構?

立即聯繫浪花科技,打造堅不可摧的 API 系統

常見問題 (FAQ)

Q1: 為什麼登出後舊的 Token 還是可以拿來打 API?

這通常是因為 JWT 的黑名單 (Blacklist) 機制沒有啟用或設定錯誤。JWT 本身是無狀態的,伺服器無法主動讓客戶端手上的 Token 失效,必須依賴伺服器端的 Cache (如 Redis) 來記錄已登出的 Token ID (jti),並在每次請求時比對。請檢查 config/jwt.php 中的 blacklist_enabled 是否為 true。

Q2: Token 應該存在前端的 LocalStorage 還是 Cookie?

這是一個經典爭論。存 LocalStorage 方便但容易受到 XSS 攻擊;存 HttpOnly Cookie 可以防 XSS 但要處理 CSRF 問題。對於 API 服務,通常建議存 LocalStorage 但必須嚴格過濾所有前端輸出來防堵 XSS;如果安全性要求極高,可以考慮 HttpOnly Cookie 搭配 CSRF Token 方案。

Q3: Laravel 11 安裝 JWT 時出現版本衝突怎麼辦?

請確認你安裝的是 php-open-source-saver/jwt-auth 而不是已經停止維護的 tymon/jwt-auth。此外,檢查你的 PHP 版本是否符合套件要求,Laravel 11 通常需要 PHP 8.2 以上。

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