# 機能設計書 21-キャプチャ生成

## 概要

本ドキュメントは、RuoYiシステムにおけるキャプチャ（画像認証コード）生成機能の詳細設計を記述する。ログイン画面およびユーザー登録画面で表示される画像認証コードを動的に生成し、不正アクセスやボット攻撃からシステムを保護するための認証補助機能である。

### 本機能の処理概要

本機能は、ユーザーがログインまたは登録を行う際に画像認証コードを生成・表示し、人間とボットを識別するためのCAPTCHA機能を提供する。

**業務上の目的・背景**：Webアプリケーションにおいて、ログインや登録などのセキュリティ上重要な操作において、自動化されたボット攻撃（ブルートフォース攻撃、スパム登録など）からシステムを保護する必要がある。CAPTCHAは人間には解読可能だがコンピュータには解読困難な画像を生成することで、人間によるアクセスであることを確認する。

**機能の利用シーン**：
- ログイン画面でユーザー名・パスワード入力時に認証コードを入力させる場面
- ユーザー登録画面で新規アカウント作成時に不正登録を防止する場面
- 認証コード画像が読みにくい場合に画像をクリックして更新する場面

**主要な処理内容**：
1. HTTPリクエストを受信し、キャプチャタイプ（文字型/算術型）を判定
2. 指定されたタイプに応じてキャプチャ文字列と画像を生成
3. 正解となるコードをHTTPセッションに保存
4. 生成した画像をJPEG形式でHTTPレスポンスに出力
5. キャッシュ無効化ヘッダーを設定して画像の再利用を防止

**関連システム・外部連携**：
- Kaptchaライブラリ（Google製CAPTCHA生成ライブラリ）を使用
- HTTPセッションを利用した正解コードの保存

**権限による制御**：本機能は認証前に使用されるため、権限チェックは行わない。匿名ユーザーでもアクセス可能である。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | ログイン画面 | 主画面 | 画像認証コードの表示・検証処理 |
| 2 | ユーザー登録画面 | 主画面 | 画像認証コードの表示・検証処理 |

## 機能種別

画像生成処理 / セッション管理 / セキュリティ認証補助

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| type | String | No | キャプチャタイプ（"math"=算術式、"char"=文字） | 未指定または無効値の場合は処理されない |

### 入力データソース

- HTTPリクエストパラメータ（GETパラメータ）
- リクエストURL: `/captcha/captchaImage`

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 画像データ | byte[] | JPEG形式のキャプチャ画像バイナリ |
| HTTPヘッダー | - | Content-Type: image/jpeg, キャッシュ無効化ヘッダー |

### 出力先

- HTTPレスポンスストリーム（画像データ）
- HTTPセッション（正解コードの保存）

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ GET /captcha/captchaImage?type={type}

2. HTTPセッション取得
   └─ request.getSession()

3. HTTPレスポンスヘッダー設定
   ├─ Expires: 0
   ├─ Cache-Control: no-store, no-cache, must-revalidate
   ├─ Pragma: no-cache
   └─ Content-Type: image/jpeg

4. キャプチャタイプ判定
   ├─ type="math" の場合: 算術式キャプチャを生成
   ├─ type="char" の場合: 文字キャプチャを生成
   └─ その他: 処理なし

5. キャプチャ生成
   ├─ captchaProducerMath.createText() または captchaProducer.createText()
   ├─ 表示用テキストと正解コードを分離（算術式の場合）
   └─ createImage()で画像生成

6. セッション保存
   └─ session.setAttribute(Constants.KAPTCHA_SESSION_KEY, code)

7. 画像出力
   ├─ response.getOutputStream()
   ├─ ImageIO.write(bi, "jpg", out)
   └─ out.flush()

8. リソース解放
   └─ out.close()
```

### フローチャート

```mermaid
flowchart TD
    A[開始: GET /captcha/captchaImage] --> B[HTTPセッション取得]
    B --> C[レスポンスヘッダー設定]
    C --> D{type パラメータ判定}
    D -->|math| E[算術式キャプチャ生成]
    D -->|char| F[文字キャプチャ生成]
    D -->|その他| G[処理終了]
    E --> H[テキストから表示文字と正解を分離]
    H --> I[画像生成]
    F --> J[テキスト生成と画像生成]
    J --> I
    I --> K[正解コードをセッションに保存]
    K --> L[画像をレスポンスに出力]
    L --> M[ストリームクローズ]
    M --> N[終了]
    G --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 算術式形式 | 算術式タイプでは「数字 演算子 数字 = ?」形式で表示し、計算結果を正解とする | type="math"の場合 |
| BR-02 | 文字形式 | 文字タイプでは4文字のランダム文字列を表示し、そのまま正解とする | type="char"の場合 |
| BR-03 | キャッシュ無効化 | 画像はブラウザにキャッシュさせず、毎回新規生成する | 常時 |
| BR-04 | セッション保存 | 正解コードはKaptcha標準のセッションキーで保存される | 常時 |

### 計算ロジック

**算術式キャプチャの計算ロジック（KaptchaTextCreator）**：
- ランダムに0〜9の2つの数値（x, y）を生成
- ランダムに演算子（+, -, *, /）を選択
- 演算結果を計算し、「x 演算子 y = ? @ 結果」形式の文字列を生成
- 除算の場合は割り切れる組み合わせのみ使用
- 減算の場合は負数にならないよう大きい方から引く

## データベース操作仕様

### 操作別データベース影響一覧

本機能はデータベースへのアクセスを行わない。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | IOException | 画像出力時のI/Oエラー | スタックトレースを出力し、処理を終了 |
| - | Exception | 画像生成時の例外 | スタックトレースを出力し、処理を終了 |

### リトライ仕様

本機能にリトライ機能はない。エラー発生時はクライアント側で画像を再度リクエストする。

## トランザクション仕様

本機能はデータベース操作を行わないため、トランザクション管理は不要。

## パフォーマンス要件

- レスポンス時間: 100ms以内
- 画像サイズ: 約5KB以下
- 同時リクエスト: セッション単位で独立処理

## セキュリティ考慮事項

- 画像はキャッシュ無効化ヘッダーにより毎回新規生成される
- 正解コードはサーバーサイドのセッションにのみ保存され、クライアントには送信されない
- 算術式タイプはOCR対策として有効（単純な文字認識では解読困難）
- ログイン時の検証ロジック（SysLoginServiceなど）で正解コードとの照合が行われる

## 備考

- Kaptchaライブラリ（com.google.code.kaptcha）を使用
- 画像サイズ: 160x60ピクセル
- 文字タイプ: 4文字（Arial, Courierフォント）
- 算術式タイプ: 6文字（計算式表示）
- 画像スタイル: ShadowGimpy（影付き）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: 設定クラスを理解する

まず、キャプチャ生成に使用されるBeanの設定を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CaptchaConfig.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java` | 2種類のProducerBean定義（captchaProducer, captchaProducerMath） |

**読解のコツ**:
- Springの`@Bean`アノテーションにより、`captchaProducer`と`captchaProducerMath`という名前でBeanが登録される
- `Properties`オブジェクトでKaptchaの各種設定（画像サイズ、フォント、色など）を定義している

**主要処理フロー**:
- **18-44行目**: 文字タイプのcaptchaProducerBean定義。幅160px、高さ60px、4文字、ShadowGimpyスタイル
- **46-82行目**: 算術式タイプのcaptchaProducerMathBean定義。カスタムTextCreatorを使用

#### Step 2: 算術式テキスト生成ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | KaptchaTextCreator.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java` | 算術式の生成ロジック |

**読解のコツ**:
- `DefaultTextCreator`を継承し、`getText()`メソッドをオーバーライド
- 返却される文字列は「表示用テキスト@正解」の形式

**主要処理フロー**:
- **14行目**: 0〜10の数字配列を定義
- **20-23行目**: SecureRandomで2つの数値x, yと演算子を決定
- **25-72行目**: 演算子に応じた計算処理（乗算、除算、減算、加算）
- **73行目**: 「表示テキスト=?@結果」形式で文字列を返却

#### Step 3: コントローラーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SysCaptchaController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysCaptchaController.java` | メインのリクエスト処理 |

**読解のコツ**:
- `@Resource`アノテーションでname指定によるBean注入
- HttpSessionを使用した正解コードの保存

**主要処理フロー**:
- **28-32行目**: 2種類のProducerをDI注入
- **37-38行目**: GET /captcha/captchaImageのエンドポイント定義
- **43-48行目**: HTTPレスポンスヘッダーの設定（キャッシュ無効化）
- **50-65行目**: typeパラメータに応じた分岐処理
- **54-59行目**: math型の場合、@記号で表示テキストと正解を分離
- **66行目**: セッションに正解コードを保存
- **67-68行目**: JPEG形式で画像を出力

### プログラム呼び出し階層図

```
SysCaptchaController.getKaptchaImage()
    │
    ├─ HttpServletRequest.getSession()
    │
    ├─ HttpServletResponse.setHeader() / setContentType()
    │
    ├─ [type判定]
    │      │
    │      ├─ "math" → captchaProducerMath.createText()
    │      │               └─ KaptchaTextCreator.getText()
    │      │           captchaProducerMath.createImage()
    │      │
    │      └─ "char" → captchaProducer.createText()
    │                   captchaProducer.createImage()
    │
    ├─ HttpSession.setAttribute()
    │
    └─ ImageIO.write()
```

### データフロー図

```
[入力]                    [処理]                           [出力]

GETリクエスト ────────▶ SysCaptchaController ────────▶ JPEG画像
  └─ type=math/char        │                              └─ レスポンスストリーム
                           │
                           ├─▶ Producer.createText()
                           │      └─ ランダム文字列生成
                           │
                           ├─▶ Producer.createImage()
                           │      └─ BufferedImage生成
                           │
                           └─▶ Session.setAttribute()
                                  └─ 正解コード保存
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SysCaptchaController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysCaptchaController.java` | コントローラー | キャプチャ画像生成のメインエンドポイント |
| CaptchaConfig.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java` | 設定 | Kaptcha Beanの設定 |
| KaptchaTextCreator.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java` | ユーティリティ | 算術式テキスト生成 |
| BaseController.java | `ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java` | 基底クラス | コントローラー基底クラス |
