Laravel 透過中介層(middleware)自動延長 Sanctum 令牌(Token)效期

Laravel Sanctum 預設的令牌(token)是固定效期的,因此要實現持續延長,需要在每次 API 請求時進行手動處理。

透過中介層自動延長 Sanctum 令牌效期

這種方法的核心概念是在每個受保護的 API 請求進入時,檢查使用者的令牌是否即將過期。如果令牌在設定的時間內(例如,10分鐘)將會過期,系統就自動產生一個新的令牌並替換掉舊的,然後將新令牌放在 HTTP 回應的標頭(Header)中傳回給客戶端。

步驟一:建立自定義的中介層 (Middleware)

首先,需要建立一個新的中介層。開啟終端機,執行以下 Artisan 指令:

php artisan make:middleware RefreshSanctumToken

步驟二:編輯中介層程式碼

開啟新建立的檔案 app/Http/Middleware/RefreshSanctumToken.php,並將其內容替換為以下程式碼。這個中介層會在每個請求處理後,檢查令牌的過期時間。

<?php

namespace App\Http\Middleware;

use Closure;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class RefreshSanctumToken
{
    /**
     * 處理傳入的請求。
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function handle(Request $request, Closure $next): Response
    {
        // 先讓請求通過,讓控制器(controller)的邏輯被執行。
        $response = $next($request);

        // 檢查使用者是否已通過 Sanctum 認證,且目前操作的令牌為 API 令牌。
        if ($request->user() && $request->user()->currentAccessToken()) {
            $token = $request->user()->currentAccessToken();
            $expiresAt = $token->expires_at;

            // 設定一個閾值,例如在令牌即將在 30 分鐘內過期時才更新。
            $threshold = Carbon::now()->addMinutes(30);

            // 如果令牌的過期時間在閾值之前,則表示即將過期。
            if ($expiresAt && $expiresAt->lt($threshold)) {
                // 刪除舊的令牌。
                $token->delete();
                
                // 創建一個新的令牌,並設定新的過期時間。
                $newToken = $request->user()->createToken('api_token', ['*'], Carbon::now()->addMinutes(config('sanctum.expiration')));

                // 將新令牌放入回應的 HTTP 標頭中,回傳給客戶端。
                $response->header('X-New-Sanctum-Token', $newToken->plainTextToken);
            }
        }

        return $response;
    }
}

步驟三:註冊中介層

開啟 bootstrap/app.php 檔案,將剛剛建立的中介層新增到 api 中介層群組中。這會確保您的中介層在每個 API 請求時都會被執行。

->withMiddleware(function (Middleware $middleware) {        
        $middleware->alias([            
            // 在這裡加入您的自定義中介層
            'refresh_sanctum_token' => \App\Http\Middleware\RefreshSanctumToken::class,
        ]);
    })

步驟四:客戶端處理新令牌

此外,考慮到使用者的不同需求,可為不同的 API endpoint 設定不同的令牌過期時間。例如,對於需要頻繁訪問的應用程式,可以設定較長的過期時間,而對於安全性要求較高的操作,可以縮短令牌的有效期。在設計 API 介面時,務必考慮這些因素,以提升整體的使用者體驗和安全性。

這一步非常重要。在您的前端應用程式中(例如,使用 Vue.js 或 React 的 SPA),當您發送 API 請求並收到回應後,需要檢查回應的標頭中是否有 X-New-Sanctum-Token。如果有,就用新令牌取代本地儲存的舊令牌。

import axios from 'axios';

// 建立一個 Axios 實例,方便集中處理。
const api = axios.create({
    baseURL: '/api',
});

// 在回應攔截器中處理新令牌。
api.interceptors.response.use(
    response => {
        const newToken = response.headers['x-new-sanctum-token'];
        if (newToken) {
            // 在這裡將新令牌儲存到瀏覽器的本地儲存中。
            localStorage.setItem('sanctum_token', newToken);
            console.log('令牌已自動延長!');
        }
        return response;
    },
    error => {
        return Promise.reject(error);
    }
);

export default api;

透過以上步驟,您的應用程式將會自動且無縫地延長使用者的令牌效期,大幅提升使用者體驗。

在開發過程中,對於使用者的安全性與便利性是相當重要的。使用 Laravel Sanctum 可以讓我們有效管理 API 的身份驗證,確保只有授權的使用者能夠訪問特定資源。這對於任何需要身份驗證的應用程式都是關鍵的,尤其是在處理敏感資料時。為了進一步提高安全性,您可以考慮使用 HTTPS 加密通訊,這樣不僅可以保護令牌不被竊取,還能確保所有傳輸的資料都受到保護。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *


內容索引