# 画面設計書 18-パスワード変更

## 概要

本ドキュメントは、RuoYi後台管理システムにおけるパスワード変更画面の設計仕様を定義するものである。

### 本画面の処理概要

パスワード変更画面は、ログインユーザーが自身のログインパスワードを変更するためのモーダルダイアログ形式の画面である。旧パスワードの確認と新パスワードの入力・確認を行い、パスワードポリシーに準拠した変更を実施する。

**業務上の目的・背景**：セキュリティ上の理由から、ユーザーは定期的にパスワードを変更する必要がある。本画面は、旧パスワードの検証を必須とすることで不正なパスワード変更を防止し、システムで設定されたパスワードポリシー（文字種、長さ等）に準拠したパスワード設定を強制する。

**画面へのアクセス方法**：プロフィール画面（No.16）の「修改密码」タブ内の「重置密码」リンク、または直接URLでアクセスする。URLパターンは `/system/user/profile/resetPwd` である。

**主要な操作・処理内容**：
1. ログイン名（読み取り専用）の表示
2. 旧パスワードの入力と検証
3. 新パスワードの入力（ポリシー表示付き）
4. 確認パスワードの入力と一致チェック
5. 保存ボタンでパスワード変更を実行

**画面遷移**：
- 遷移元：プロフィール画面（No.16）
- 遷移先：なし（保存後はモーダルを閉じてプロフィール画面に戻る）

**権限による表示制御**：ログインユーザー自身のパスワードのみ変更可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | プロファイル管理 | 主機能 | パスワード変更処理 |
| 1 | ユーザー管理 | 補助機能 | パスワード更新のDB処理 |

## 画面種別

編集（モーダルダイアログ形式・パスワード変更専用）

## URL/ルーティング

| メソッド | URL | 説明 |
|---------|-----|------|
| GET | /system/user/profile/resetPwd | パスワード変更画面表示 |
| POST | /system/user/profile/resetPwd | パスワード変更保存 |
| GET | /system/user/profile/checkPassword | 旧パスワード検証 |

## 入出力項目

### 入力項目

| No | 項目名 | 物理名 | 型 | 桁数 | 必須 | 初期値 | バリデーション |
|----|--------|--------|----|----|------|--------|--------------|
| 1 | ユーザーID | userId | hidden | - | ○ | ログインユーザーID | - |
| 2 | ログイン名 | loginName | text | - | - | ログインユーザー名 | 読み取り専用 |
| 3 | 旧パスワード | oldPassword | password | - | ○ | - | 必須、リモート検証 |
| 4 | 新パスワード | newPassword | password | 5-20 | ○ | - | 5-20文字、ポリシー準拠 |
| 5 | 確認パスワード | confirmPassword | password | - | ○ | - | newPasswordと一致 |

## 表示項目

| No | 項目名 | 説明 |
|----|--------|------|
| 1 | ログイン名 | 現在ログイン中のユーザー名（編集不可） |
| 2 | パスワードポリシー | sys.account.chrtypeの設定に応じた入力規則 |

## イベント仕様

### 1-画面初期表示

| 項目 | 内容 |
|------|------|
| トリガー | 画面アクセス時 |
| 処理内容 | 1. ログインユーザー情報を取得<br>2. ユーザーIDをhiddenに設定<br>3. ログイン名を読み取り専用で表示<br>4. パスワードポリシー（chrtype）に応じたヒントを表示 |
| 呼び出しAPI | GET /system/user/profile/resetPwd |
| 遷移先 | - |

### 2-旧パスワード入力時（リモートバリデーション）

| 項目 | 内容 |
|------|------|
| トリガー | 旧パスワード入力欄からフォーカスアウト時 |
| 処理内容 | 1. Ajaxで旧パスワードをサーバーに送信<br>2. passwordService.matchesで検証<br>3. 不一致の場合「原密码错误」を表示 |
| 呼び出しAPI | GET /system/user/profile/checkPassword |
| 遷移先 | - |

### 3-新パスワード入力時

| 項目 | 内容 |
|------|------|
| トリガー | 新パスワード入力時 |
| 処理内容 | 1. 5-20文字の長さチェック<br>2. specialSign（chrtypeに応じたポリシー）チェック |
| 呼び出しAPI | - |
| 遷移先 | - |

### 4-確認パスワード入力時

| 項目 | 内容 |
|------|------|
| トリガー | 確認パスワード入力時 |
| 処理内容 | equalTo: "#newPassword"で一致チェック |
| 呼び出しAPI | - |
| 遷移先 | - |

### 5-保存ボタン押下（submitHandler）

| 項目 | 内容 |
|------|------|
| トリガー | ダイアログの「確定」ボタン押下時 |
| 処理内容 | 1. フォームバリデーション実行<br>2. checkpwd()でポリシーチェック<br>3. Ajax POSTでパスワード変更リクエスト<br>4. サーバー側で旧パスワード再検証<br>5. 新パスワードが旧と同じでないかチェック<br>6. 新しいsaltを生成してパスワード暗号化<br>7. DB更新後、セッション情報を更新 |
| 呼び出しAPI | POST /system/user/profile/resetPwd |
| 遷移先 | プロフィール画面（成功時） |

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 保存ボタン押下 | sys_user | UPDATE | パスワードとsaltの更新 |

### テーブル別更新項目詳細

#### sys_user

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | password | 暗号化された新パスワード | ShiroUtils.randomSalt()で生成したsaltを使用 |
| UPDATE | salt | 新しいsalt値 | ランダム生成 |

## メッセージ仕様

| No | 種別 | メッセージ | 表示条件 |
|----|------|----------|----------|
| 1 | 成功 | 操作成功 | パスワード変更成功時 |
| 2 | エラー | 请输入原密码 | 旧パスワード未入力時 |
| 3 | エラー | 原密码错误 | 旧パスワード不一致時 |
| 4 | エラー | 请输入新密码 | 新パスワード未入力時 |
| 5 | エラー | 密码不能小于5个字符 | 5文字未満の場合 |
| 6 | エラー | 密码不能大于20个字符 | 20文字超過の場合 |
| 7 | エラー | 请再次输入新密码 | 確認パスワード未入力時 |
| 8 | エラー | 两次密码输入不一致 | パスワード不一致時 |
| 9 | エラー | 修改密码失败，旧密码错误 | サーバー側旧パスワードエラー |
| 10 | エラー | 新密码不能与旧密码相同 | 新旧パスワード同一時 |
| 11 | エラー | 修改密码异常，请联系管理员 | DB更新失敗時 |

## パスワードポリシー（chrtype）

| chrtype値 | ポリシー内容 | 表示メッセージ |
|-----------|-------------|---------------|
| 0 | 制限なし | （表示なし） |
| 1 | 数字のみ | 密码只能为0-9数字 |
| 2 | 英字のみ | 密码只能为a-z和A-Z字母 |
| 3 | 英数字必須 | 密码必须包含（字母，数字） |
| 4 | 英数字+特殊文字 | 密码必须包含（字母，数字，特殊字符!@#$%^&*()-=_+） |

## 例外処理

| 例外パターン | 対応処理 |
|------------|---------|
| 旧パスワード不一致 | リモートバリデーションでエラー表示 |
| 新パスワードポリシー違反 | specialSignバリデーションでエラー表示 |
| 新旧パスワード同一 | サーバーエラーメッセージ表示 |
| DB更新失敗 | エラーメッセージ表示 |

## 備考

- パスワードはShiro方式（MD5 + salt）で暗号化
- saltはShiroUtils.randomSalt()でランダム生成
- sys.account.chrtype設定でパスワードポリシーを制御
- セッション内のユーザー情報も更新される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SysProfileController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java` | resetPwd()とcheckPassword()メソッド |

**主要処理フロー**:
1. **60-66行目**: `checkPassword()` メソッド - 旧パスワードの検証（passwordService.matches）
2. **68-73行目**: `resetPwd()` GET - 画面表示
3. **76-98行目**: `resetPwd()` POST - パスワード変更処理

#### Step 2: 画面テンプレートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | resetPwd.html | `ruoyi-admin/src/main/resources/templates/system/user/profile/resetPwd.html` | バリデーション、ポリシー表示 |

**主要処理フロー**:
- **9行目**: hidden項目でuserId保持
- **13行目**: ログイン名（読み取り専用）
- **19行目**: 旧パスワード入力欄
- **25行目**: 新パスワード入力欄
- **26-35行目**: パスワードポリシー表示（chrtype条件分岐）
- **41行目**: 確認パスワード入力欄
- **50-93行目**: jQueryValidateルール定義
- **95-101行目**: submitHandler（checkpwd実行）

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

```
プロフィール画面 [修改密码タブ] / 直接アクセス
    │
    └─ SysProfileController.resetPwd() GET       ← GET /profile/resetPwd
           └─ userService.selectUserById()       ← ユーザー情報取得
                  │
                  └─ resetPwd.html 表示
                         │
                         ├─ [旧パスワード] フォーカスアウト
                         │      └─ Ajax → SysProfileController.checkPassword()
                         │             └─ passwordService.matches()  ← 検証
                         │
                         ├─ [新パスワード] 入力
                         │      └─ specialSign バリデーション（chrtype準拠）
                         │
                         ├─ [確認パスワード] 入力
                         │      └─ equalTo バリデーション
                         │
                         └─ [確定]ボタン
                                │
                                ├─ $.validate.form()
                                ├─ checkpwd(chrtype, password)
                                │
                                └─ Ajax POST → SysProfileController.resetPwd()
                                       ├─ passwordService.matches()  ← 再検証
                                       ├─ ShiroUtils.randomSalt()   ← salt生成
                                       ├─ passwordService.encryptPassword()
                                       ├─ userService.resetUserPwd()  ← DB更新
                                       └─ setSysUser()  ← セッション更新
```

### データフロー図

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

旧パスワード
(oldPassword)     SysProfileController.checkPassword()
     │                   │
     └─────────▶ passwordService.matches()  ─────▶ true/false

新パスワード
(newPassword)     SysProfileController.resetPwd()
     │                   │
     │            ├─ passwordService.matches(旧)  ─▶ 検証
     │            ├─ passwordService.matches(新)  ─▶ 同一チェック
     │            │
     │            ├─ ShiroUtils.randomSalt()      ─▶ salt生成
     │            ├─ encryptPassword()            ─▶ ハッシュ化
     │            │
     │            └─ userService.resetUserPwd()
     │                   │
     ▼                   ▼
FormData ────────▶ sys_user UPDATE (password, salt)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SysProfileController.java | `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java` | コントローラー | resetPwd(), checkPassword()メソッド |
| resetPwd.html | `ruoyi-admin/src/main/resources/templates/system/user/profile/resetPwd.html` | テンプレート | パスワード変更フォーム |
| SysPasswordService.java | `ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysPasswordService.java` | サービス | パスワード検証・暗号化 |
| ShiroUtils.java | `ruoyi-common/src/main/java/com/ruoyi/common/utils/ShiroUtils.java` | ユーティリティ | randomSalt()メソッド |
| ISysUserService.java | `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java` | インターフェース | resetUserPwd()メソッド |
| SysUserMapper.xml | `ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml` | Mapper | resetUserPwd SQL |
