> ## 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()で取得する理由を、期限付きリンクの実装例で解説します。

## このページの目的

期限付きの共有リンクで、発行時に決めた条件をそのまま使いたい場合は、URLの署名検証に加えて**値をどこから取得するか**を揃えます。
このページでは、レポートの種類と出力形式をURLに含め、プレビュー用のJSONを返す例で説明します。

対象はLaravel 13です。URL生成全般は[URL生成](/jp/urls)、入力取得の基本は[HTTPリクエスト](/jp/requests)を参照してください。

<Warning>
  署名はリクエスト全体を保護するものではありません。フォームやJSONの本文は署名対象外です。
  署名済みクエリ値は、署名検証後に `$request->query('format')` のように取得してください。
  `input()`、`all()`、動的プロパティでは、署名されていない本文の値を取得する可能性があります。GETリクエストでもこの区別は必要です。
</Warning>

## 署名で保護される範囲

| 要素 | 扱い |
| - | - |
| URLのパス | 署名検証の対象 |
| クエリ文字列 | 原則として署名検証の対象。検証から除外したパラメータを除く |
| スキーム・ホスト | 通常は署名に含む。相対署名では含めない |
| フォーム・JSONの本文 | 署名の対象外 |
| 有効期限 | `temporarySignedRoute()` が追加し、検証時に期限切れを確認 |

`input()` はクエリ文字列だけでなく本文も扱うAPIです。Laravelはこれらの入力を統合する際、本文の値をクエリ文字列より優先します。
一方、`query()` はクエリ文字列だけを取得します。

署名検証が成功したことと、その後に読み取った値が署名済みであることは別の確認事項です。

```mermaid theme={null}
flowchart TD
    A["期限付きURLでアクセス"] --> B{"signedミドルウェア<br>署名・有効期限を検証"}
    B -->|無効| C["403レスポンス"]
    B -->|有効| D["query()で<br>署名済みクエリ値を取得"]
    D --> E["値の形式・許可範囲を検証"]
    E --> F["プレビューを返す"]
```

## 期限付きプレビューリンクを実装する

### 1. 検証するルートを定義する

`routes/web.php` に、署名を必須とする名前付きルートを定義します。
ここではDBやファイルを操作せず、受け取った条件だけを返します。

```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` ミドルウェアが、クロージャの実行前に署名と有効期限を検証します。無効なら `403` を返します。
* `query()` で、処理に使う値をクエリ文字列から明示的に取得します。
* バリデーションは取得した配列に対して行います。署名検証は値の型や業務上の許可範囲を保証するものではありません。

<Info>
  この例で `Validator::make()` に渡しているのは、`query()` で取り出した値だけです。
  署名済みクエリの検証を目的とする箇所で `$request->all()` に置き換えると、本文を含む入力を扱うことになります。
</Info>

### 2. 信頼できる発行処理でURLを生成する

名前付きルートの登録後、リンクを発行する処理で次のコードを使います。
`report` と `format` はパスのプレースホルダーではないため、クエリ文字列に追加されます。

```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が使用する予約済みパラメータなので、業務用のパラメータ名として渡さないでください。

実際のアプリケーションで発行処理を公開する場合は、任意の条件で誰でもリンクを発行できる状態にせず、必要な[認証](/jp/authentication)や[認可](/jp/authorization)を行ってください。

### 3. 通常の利用を確認する

発行したURLをそのまま開くと、有効期限内であれば次のJSONが返ります。

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

リンクの有効期限が切れた場合は、ルートの `signed` ミドルウェアが `403` を返します。
署名付きURLは使い捨てトークンではありません。この例では、期限内の同じURLを再利用できます。
一度だけ利用させたい場合は、署名とは別に使用済み状態を管理する必要があります。

## 検証から除外する値を分ける

フロントエンドが追加するページ番号などを許可したい場合、`hasValidSignatureWhileIgnoring(['page'])` で署名検証から除外できます。
ただし、除外した値は誰でも変更できるため、署名済み条件として扱わないでください。

たとえば、表示用の `page` と、発行時に固定する `report`、`format` は役割が異なります。
対象データ、受信者、料金などの判断に使う値を、利便性だけを理由に除外しないようにします。

<Warning>
  上の実装例は通常の `signed` ミドルウェアを使っているため、`page` も除外していません。
  クエリパラメータを追加して使いたい場合は、生成側と検証側で何を署名対象にするかを先に決めてください。
</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')` に変更します。
相対署名でも本文は署名されないので、`query()` で取得する方針は変わりません。

## 実装時のチェックリスト

* 受信ルートで署名検証を必須にしている。
* 署名済みクエリ値を `query()` から取得している。
* 値の形式や許可範囲を別途検証している。
* 署名検証から除外した値を、発行時に固定された条件として使っていない。
* 絶対署名・相対署名の設定を生成側と検証側で揃えている。
* URLを知っていることと、ログインユーザーの権限を同一視していない。

## 関連ページと一次情報

* [URL生成](/jp/urls)：署名付きURLのAPIと無効な署名へのレスポンス
* [HTTPリクエスト](/jp/requests)：入力値とクエリ文字列の取得
* [バリデーション](/jp/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生成](/jp/urls.md)
- [Basic client - Laravel Bluesky](/jp/packages/laravel-bluesky/basic-client.md)
- [イベントとリスナー](/jp/events.md)
- [Laravel Prompts](/jp/prompts.md)
- [Core — AT Protocol コア操作](/jp/packages/laravel-bluesky/core.md)


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