# 機能設計書 20-ユーザー登録

## 概要

本ドキュメントは、RuoYiシステムにおけるユーザー登録機能の詳細設計を記述する。ユーザー登録機能は、新規ユーザーが自分でアカウントを作成するためのセルフサービス機能である。

### 本機能の処理概要

ユーザー登録機能は、ユーザー自身が新しいアカウントを作成できる機能を提供する。キャプチャ検証、入力値検証、ユーザー名重複チェック、パスワードハッシュ化などを行い、安全にユーザーを登録する。

**業務上の目的・背景**：システムへの新規ユーザー参加を促進し、管理者の負担を軽減する。ただし、セキュリティ上の理由から、デフォルトでは無効化されており、運用方針に応じて有効化する設計となっている。

**機能の利用シーン**：
- 新規ユーザーがシステムに参加する際
- 一般公開サービスでのアカウント作成
- 招待制でない環境でのユーザー自己登録

**主要な処理内容**：
1. 登録画面の表示
2. キャプチャ（画像認証コード）の検証
3. ユーザー名・パスワードの入力検証
4. ユーザー名の重複チェック
5. パスワードのハッシュ化
6. ユーザー情報のDB登録
7. 登録結果の非同期ログ記録

**関連システム・外部連携**：なし（自己完結型の機能）

**権限による制御**：
- 登録機能自体は認証前のため権限制御なし
- システム設定（sys.account.registerUser）で機能の有効/無効を制御

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | ユーザー登録画面 | 主画面 | 新規ユーザー情報の入力と登録処理 |
| 1 | ログイン画面 | 遷移元/遷移先 | 登録完了後のログイン、登録画面へのリンク |

## 機能種別

ユーザー登録処理 / セルフサービス

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loginName | String | Yes | ログイン名 | 2〜20文字、重複不可 |
| password | String | Yes | パスワード | 5〜20文字 |
| captcha | String | Yes（設定時） | 画像認証コード | 正しいコード |

### 入力データソース

- 画面入力

## 出力仕様

### 出力データ

#### 登録成功時

| 項目名 | 型 | 説明 |
|--------|-----|------|
| code | int | 0（成功） |
| msg | String | 空またはなし |

#### 登録失敗時

| 項目名 | 型 | 説明 |
|--------|-----|------|
| code | int | 500（エラー） |
| msg | String | エラーメッセージ |

### 出力先

- AjaxResult（JSONレスポンス）

## 処理フロー

### 処理シーケンス

```
1. 登録画面表示
   └─ GET /register リクエスト
   └─ 登録画面を表示

2. 登録処理
   └─ POST /register リクエスト
   └─ 登録機能有効性チェック（sys.account.registerUser）
   └─ SysRegisterService.register()呼び出し
      └─ キャプチャ検証
      └─ ユーザー名空チェック
      └─ パスワード空チェック
      └─ パスワード長さ検証（5〜20文字）
      └─ ユーザー名長さ検証（2〜20文字）
      └─ ユーザー名重複チェック
      └─ パスワード更新日を設定
      └─ ユーザー名をuserNameにも設定
      └─ ソルト生成
      └─ パスワードハッシュ化
      └─ ユーザーDB登録
      └─ 登録成功ログ記録（非同期）
   └─ 結果レスポンス返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{GET/POST}
    B -->|GET| C[登録画面表示]

    B -->|POST| D{登録機能有効?}
    D -->|No| E[エラー: 登録機能無効]
    D -->|Yes| F{キャプチャ検証}
    F -->|NG| G[エラー: 验证码错误]
    F -->|OK| H{ユーザー名空?}
    H -->|Yes| I[エラー: 用户名不能为空]
    H -->|No| J{パスワード空?}
    J -->|Yes| K[エラー: 密码不能为空]
    J -->|No| L{パスワード長?}
    L -->|NG| M[エラー: 5〜20文字]
    L -->|OK| N{ユーザー名長?}
    N -->|NG| O[エラー: 2〜20文字]
    N -->|OK| P{ユーザー名重複?}
    P -->|Yes| Q[エラー: 账号已存在]
    P -->|No| R[ユーザー情報設定]
    R --> S[ソルト生成]
    S --> T[パスワードハッシュ化]
    T --> U[DB登録]
    U --> V{登録成功?}
    V -->|No| W[エラー: 注册失败]
    V -->|Yes| X[成功ログ記録]
    X --> Y[成功レスポンス]

    C --> Z[終了]
    E --> Z
    G --> Z
    I --> Z
    K --> Z
    M --> Z
    O --> Z
    Q --> Z
    W --> Z
    Y --> Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-20-01 | 機能有効性 | sys.account.registerUser='true'の場合のみ登録可能 | 登録リクエスト時 |
| BR-20-02 | キャプチャ必須 | 画像認証コードが有効な場合、検証必須 | 登録リクエスト時 |
| BR-20-03 | ユーザー名長さ | 2〜20文字 | 登録時 |
| BR-20-04 | パスワード長さ | 5〜20文字 | 登録時 |
| BR-20-05 | ユーザー名一意 | 既存ユーザーと重複不可 | 登録時 |
| BR-20-06 | デフォルト無効 | 登録機能はデフォルトで無効（false） | 初期設定 |
| BR-20-07 | ユーザータイプ | 登録ユーザーのuserTypeは'01'（登録ユーザー） | 登録時 |
| BR-20-08 | 登録ログ | 登録成功時に非同期でログ記録 | 登録成功時 |

### 計算ロジック

#### パスワードハッシュ化

```
hashedPassword = MD5(loginName + password + salt)
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 重複チェック | sys_user | SELECT | ログイン名の重複確認 |
| ユーザー登録 | sys_user | INSERT | 新規ユーザーを登録 |
| ログ記録 | sys_logininfor | INSERT | 登録成功のログ記録 |

### テーブル別操作詳細

#### sys_user

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | login_name | WHERE login_name = ? | 重複チェック |
| INSERT | login_name, user_name, password, salt, user_type, pwd_update_date, create_time | 入力値、ソルト、ユーザータイプ'01' | 新規登録 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 機能無効エラー | sys.account.registerUser!=true | 管理者に登録機能の有効化を依頼 |
| - | キャプチャエラー | 画像認証コード不一致 | 正しいコードを入力 |
| - | 必須エラー | ユーザー名またはパスワードが空 | 入力を完了させる |
| - | 長さエラー | パスワード5〜20文字、ユーザー名2〜20文字の範囲外 | 範囲内の文字数で入力 |
| - | 重複エラー | ユーザー名が既存ユーザーと重複 | 別のユーザー名を使用 |
| - | 登録失敗 | DB登録に失敗 | 管理者に連絡 |

### リトライ仕様

特になし

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

- ユーザー登録はuserMapper.insertUser()の単一INSERT操作
- ログ記録は非同期で実行（AsyncManager）

## パフォーマンス要件

- 登録処理：2秒以内にレスポンス
- パスワードハッシュ計算：100ms以内

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

- パスワードはMD5+ソルトでハッシュ化（平文保存しない）
- キャプチャによるボット対策
- デフォルト無効による不正登録防止
- ユーザー名重複チェックによる既存アカウントへの影響防止
- 登録ユーザーは専用のユーザータイプ（'01'）で区別

## 備考

- 登録機能はデフォルトで無効。有効化するには sys_config テーブルの sys.account.registerUser を 'true' に設定する
- 登録ユーザーのユーザータイプは '01'（UserConstants.REGISTER_USER_TYPE）
- userName には loginName と同じ値が設定される
- パスワード更新日（pwd_update_date）は登録時の日時が設定される

---

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

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

### 推奨読解順序

#### Step 1: エントリーポイントを理解する

コントローラーが処理の起点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SysRegisterController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java` | 登録画面表示とAjax登録処理 |

**主要処理フロー**:
- **29-33行目**: register() - GET リクエスト、画面表示
- **35-45行目**: ajaxRegister() - POST リクエスト、登録処理
- **39-42行目**: sys.account.registerUser設定のチェック

#### Step 2: 登録サービスを理解する

登録ロジックの中核を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SysRegisterService.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysRegisterService.java` | 登録ロジック全体 |

**主要処理フロー**:
- **35-82行目**: register() - メイン登録処理
- **39-42行目**: キャプチャ検証
- **43-50行目**: ユーザー名・パスワード空チェック
- **51-59行目**: 長さ検証
- **61-64行目**: ユーザー名重複チェック
- **67-70行目**: ユーザー情報設定（ソルト、パスワードハッシュ）
- **71-79行目**: DB登録とログ記録

#### Step 3: パスワードサービスを理解する

パスワードハッシュ化を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SysPasswordService.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysPasswordService.java` | パスワードハッシュ化 |

**主要処理フロー**:
- **81-84行目**: encryptPassword() - パスワードハッシュ化

#### Step 4: ユーザーサービスを理解する

DB登録処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SysUserServiceImpl.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java` | ユーザー登録DB操作 |

**主要処理フロー**:
- **239-243行目**: registerUser() - DB登録、ユーザータイプ設定

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

```
SysRegisterController
    │
    ├─ register() [GET]
    │      └─ return "register"
    │
    └─ ajaxRegister() [POST]
           ├─ configService.selectConfigByKey("sys.account.registerUser")
           └─ SysRegisterService.register()
                  ├─ キャプチャ検証
                  ├─ 入力値検証（空、長さ）
                  ├─ userService.checkLoginNameUnique()
                  │      └─ SysUserMapper.checkLoginNameUnique()
                  ├─ user.setPwdUpdateDate()
                  ├─ user.setUserName()
                  ├─ user.setSalt(ShiroUtils.randomSalt())
                  ├─ passwordService.encryptPassword()
                  │      └─ MD5(loginName + password + salt)
                  ├─ userService.registerUser()
                  │      ├─ user.setUserType("01")
                  │      └─ userMapper.insertUser()
                  └─ AsyncFactory.recordLogininfor()
```

### データフロー図

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

loginName    ───▶ Controller         ───▶ AjaxResult
password           ↓                        (success/error)
                   設定チェック
                   ↓
                   SysRegisterService.register()
                   ↓
              ┌────┴────────────────┐
              ↓                     ↓
         Validation            DB Registration
         (captcha,             (uniqueness check,
          empty,               salt generation,
          length)              password hash,
              ↓                insert user)
              └────────┬────────────┘
                       ↓
                 Success/Failure
                       ↓
              ┌────────┴────────┐
              ↓                 ↓
         recordLogininfor   AjaxResult
         (非同期)           返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SysRegisterController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/` | コントローラー | HTTPリクエストのハンドリング |
| SysRegisterService.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/` | サービス | 登録ロジック |
| SysPasswordService.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/` | サービス | パスワードハッシュ化 |
| ISysUserService.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/` | インターフェース | ユーザーサービス契約 |
| SysUserServiceImpl.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/` | サービス実装 | ユーザーDB操作 |
| SysUserMapper.java | `ruoyi-system/src/main/java/com/ruoyi/system/mapper/` | Mapper | データアクセス層インターフェース |
| SysUserMapper.xml | `ruoyi-system/src/main/resources/mapper/system/` | MyBatis XML | SQL定義 |
| ISysConfigService.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/` | インターフェース | 設定サービス契約 |
| AsyncFactory.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/` | ファクトリー | 非同期タスク生成 |
| ShiroUtils.java | `ruoyi-common/src/main/java/com/ruoyi/common/utils/` | ユーティリティ | ソルト生成など |
| UserConstants.java | `ruoyi-common/src/main/java/com/ruoyi/common/constant/` | 定数 | ユーザー関連定数 |
