> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 正確處理簽章 URL 的輸入

> 透過限時連結的實作範例，說明 Laravel 13 簽章 URL 保護的範圍，以及為何要用 query() 取得已簽章的 query 值。

## 本頁目的

在限時分享連結中，若想直接使用核發時決定的條件，除了驗證 URL 簽章之外，還需要統一**從哪裡取得值**。
本頁以一個範例說明：在 URL 中包含報表類型與輸出格式，並回傳預覽用的 JSON。

本頁適用於 Laravel 13。URL 產生的整體說明請參閱 [URL 生成](/zh-TW/urls)，取得輸入的基礎請參閱 [HTTP Request](/zh-TW/requests)。

<Warning>
  簽章並不保護整個請求。表單與 JSON 的 body 不在簽章範圍內。
  已簽章的 query 值，請在簽章驗證後以 `$request->query('format')` 這類方式取得。
  使用 `input()`、`all()` 或動態屬性時，可能會取得未簽章的 body 值。GET 請求同樣需要做此區分。
</Warning>

## 簽章保護的範圍

| 元素 | 處理方式 |
| - | - |
| URL 路徑 | 納入簽章驗證 |
| query string | 原則上納入簽章驗證，但排除於驗證之外的參數除外 |
| scheme 與 host | 通常包含在簽章中，相對簽章時不包含 |
| 表單與 JSON 的 body | 不在簽章範圍內 |
| 有效期限 | 由 `temporarySignedRoute()` 加入，驗證時檢查是否過期 |

`input()` 不僅處理 query string，也會處理 body。Laravel 在合併這些輸入時，body 的值優先於 query string 的值。
相對地，`query()` 只會取得 query string 的值。

簽章驗證成功，與之後讀取的值是否已簽章，是兩件需要分別確認的事。

```mermaid theme={null}
flowchart TD
    A["透過限時 URL 存取"] --> B{"signed middleware<br>驗證簽章與有效期限"}
    B -->|無效| C["403 回應"]
    B -->|有效| D["以 query()<br>取得已簽章的 query 值"]
    D --> E["驗證值的格式與允許範圍"]
    E --> F["回傳預覽"]
```

## 實作限時預覽連結

### 1. 定義進行驗證的路由

在 `routes/web.php` 中定義必須帶有簽章的具名路由。
這裡不操作資料庫或檔案，只回傳收到的條件。

```php theme={null}
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Validator;

Route::get('/reports/preview', function (Request $request) {
    $options = Validator::make([
        'report' => $request->query('report'),
        'format' => $request->query('format'),
    ], [
        'report' => ['required', 'string', 'in:monthly,annual'],
        'format' => ['required', 'string', 'in:csv,pdf'],
    ])->validate();

    return response()->json($options);
})->middleware('signed')->name('reports.preview');
```

* `signed` middleware 會在 closure 執行前驗證簽章與有效期限。若無效則回傳 `403`。
* 使用 `query()` 明確地從 query string 取得處理所需的值。
* 驗證是針對取得的陣列進行。簽章驗證並不保證值的型別或業務上允許的範圍。

<Info>
  本範例傳給 `Validator::make()` 的只有以 `query()` 取出的值。
  若在用來驗證已簽章 query 值的地方改用 `$request->all()`，就會處理到包含 body 在內的輸入。
</Info>

### 2. 在可信任的核發流程中產生 URL

註冊具名路由後，在核發連結的處理中使用以下程式碼。
`report` 與 `format` 不是路徑的佔位符，因此會被加入 query string。

```php theme={null}
use Illuminate\Support\Facades\URL;

$url = URL::temporarySignedRoute(
    'reports.preview',
    now()->addMinutes(30),
    ['report' => 'monthly', 'format' => 'csv'],
);
```

此 URL 除了指定的條件外，還包含 `expires` 與 `signature`。
`expires` 與 `signature` 是 Laravel 使用的保留參數，請勿將其作為業務用的參數名稱。

在實際應用程式中公開核發流程時，請勿讓任何人都能以任意條件核發連結，並進行必要的[認證](/zh-TW/authentication)與[授權](/zh-TW/authorization)。

### 3. 確認正常使用

在有效期限內直接開啟核發的 URL，會回傳以下 JSON。

```json theme={null}
{
  "report": "monthly",
  "format": "csv"
}
```

連結過期時，路由上的 `signed` middleware 會回傳 `403`。
簽章 URL 並非一次性 token。在本範例中，有效期限內可重複使用同一個 URL。
若只允許使用一次，需要在簽章之外另行管理已使用狀態。

## 區分排除於驗證之外的值

若想允許前端加上的頁碼等參數，可以透過 `hasValidSignatureWhileIgnoring(['page'])` 將其排除於簽章驗證之外。
不過，被排除的值任何人都能修改，因此請勿將其視為已簽章的條件。

例如，顯示用的 `page` 與核發時固定的 `report`、`format` 作用不同。
請勿僅為了方便，就排除用來判斷目標資料、收件者、費用等的值。

<Warning>
  上面的實作範例使用一般的 `signed` middleware，因此 `page` 也沒有被排除。
  若需要加上 query 參數，請先決定產生端與驗證端各自要將哪些內容納入簽章。
</Warning>

## 使用相對簽章時

在簽章中不包含網域的設計下，需搭配產生時的 `absolute: false` 與驗證時的 `signed:relative`。

```php theme={null}
$url = URL::temporarySignedRoute(
    'reports.preview',
    now()->addMinutes(30),
    ['report' => 'monthly', 'format' => 'csv'],
    absolute: false,
);
```

此時，請將前面路由的 `middleware('signed')` 改為 `middleware('signed:relative')`。
即使使用相對簽章，body 也不會被簽章，因此以 `query()` 取得值的原則不變。

## 實作檢查清單

* 接收路由強制要求簽章驗證。
* 以 `query()` 取得已簽章的 query 值。
* 另外驗證值的格式與允許範圍。
* 未將排除於簽章驗證之外的值當作核發時固定的條件使用。
* 產生端與驗證端的絕對簽章、相對簽章設定一致。
* 未將知道 URL 視同已登入使用者的權限。

## 相關頁面與一手資料

* [URL 生成](/zh-TW/urls)：簽章 URL 的 API 與對無效簽章的回應
* [HTTP Request](/zh-TW/requests)：取得輸入值與 query string
* [驗證](/zh-TW/validation)：驗證輸入格式與允許的值
* [Laravel 官方文件：Signed URLs](https://github.com/laravel/docs/blob/13.x/urls.md#signed-urls)
* [Laravel 官方文件：Retrieving input from the query string](https://github.com/laravel/docs/blob/13.x/requests.md#retrieving-input-from-the-query-string)
* [Laravel Framework：UrlGenerator](https://github.com/laravel/framework/blob/13.x/src/Illuminate/Routing/UrlGenerator.php)
* [Laravel Framework：ValidateSignature](https://github.com/laravel/framework/blob/13.x/src/Illuminate/Routing/Middleware/ValidateSignature.php)


## Related topics

- [URL 生成](/zh-TW/urls.md)
- [Basic client - Laravel Bluesky](/zh-TW/packages/laravel-bluesky/basic-client.md)
- [事件與監聽器](/zh-TW/events.md)
- [Session](/zh-TW/session.md)
- [驗證](/zh-TW/validation.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.