|
|
@@ -0,0 +1,186 @@
|
|
|
+# Users + Admins 表合并设计文档
|
|
|
+
|
|
|
+**日期**: 2026-05-13
|
|
|
+**状态**: 已定稿,待实施
|
|
|
+
|
|
|
+## 1. 背景
|
|
|
+
|
|
|
+当前系统使用两张独立的认证表:
|
|
|
+- `users` — 小程序用户(家长/孩子/规划师),加密算法 `xzyj_salt_` + MD5
|
|
|
+- `admins` — Web管理端用户(管理员/规划师),加密算法 `xzyj_admin_salt_` + MD5
|
|
|
+
|
|
|
+规划师需要在小程序端和 Web 管理端同时使用,但两套认证体系导致:
|
|
|
+- 规划师审核通过时需同步创建 admins 记录(`AdminController.guide/approve`)
|
|
|
+- 密码不同步,规划师需要两套密码
|
|
|
+- 扩展新角色需要同时修改两套系统
|
|
|
+
|
|
|
+## 2. 目标
|
|
|
+
|
|
|
+将 admins 表的功能合并到 users 表,统一认证体系,废弃 admins 表。
|
|
|
+
|
|
|
+## 3. 设计方案(4个模块)
|
|
|
+
|
|
|
+### Module 1: 数据模型合并
|
|
|
+
|
|
|
+#### users 表新增字段
|
|
|
+```sql
|
|
|
+-- 迁移SQL (DatabaseInitializer)
|
|
|
+ALTER TABLE users ADD COLUMN username VARCHAR(50) COMMENT '登录用户名(兼容admins迁移)';
|
|
|
+ALTER TABLE users ADD COLUMN status VARCHAR(20) DEFAULT 'active' COMMENT '账号状态: active/inactive/actived';
|
|
|
+ALTER TABLE users ADD INDEX idx_username (username);
|
|
|
+
|
|
|
+-- status 字段说明:
|
|
|
+-- active - 正常(小程序用户默认)
|
|
|
+-- actived - 已激活(规划师设置密码后)
|
|
|
+-- inactive - 已禁用
|
|
|
+```
|
|
|
+
|
|
|
+#### User.java 实体新增字段
|
|
|
+```java
|
|
|
+private String username; // 登录用户名
|
|
|
+private String status; // 账号状态: active/inactive/actived
|
|
|
+```
|
|
|
+
|
|
|
+#### 数据迁移逻辑 (DatabaseInitializer.runMigrations)
|
|
|
+```text
|
|
|
+遍历 admins 表所有记录:
|
|
|
+ 1. 按 phone 查询 users 表
|
|
|
+ 2. 如果 phone 已存在 users 中:
|
|
|
+ - 更新 role(如果 admins.role=teacher 且 users 是 parent,添加 teacher 角色)
|
|
|
+ - 设置 password(用 xzyj_salt_ + MD5 重新加密)
|
|
|
+ - 设置 username = admins.username(如果有)
|
|
|
+ - 设置 status = active
|
|
|
+ 3. 如果 phone 不存在 users 中:
|
|
|
+ - 在 users 表创建新用户
|
|
|
+ - 设置必要字段(phone, username, password, role, status)
|
|
|
+ - 不创建家庭(admins 没有家庭概念)
|
|
|
+ 4. 跳过没有 phone 的 admins 记录
|
|
|
+```
|
|
|
+
|
|
|
+**注意**: admins 表不删除,仅停止使用,保留作为回滚备份。
|
|
|
+
|
|
|
+### Module 2: Web登录重建
|
|
|
+
|
|
|
+#### AdminAuthController 重构
|
|
|
+- 将 `AdminMapper` 替换为 `UserMapper`
|
|
|
+- 所有查询从 `admins` 表改为 `users` 表
|
|
|
+- 加密算法从 `xzyj_admin_salt_` + MD5 改为 `xzyj_salt_` + MD5(与 UserService 一致)
|
|
|
+- `loginByPassword` 改为用 phone 查询 users 表,支持 teacher 角色
|
|
|
+- 登录时检测 `status = inactive` → 账号被禁用
|
|
|
+- 登录时检测 `role=teacher && password 为空/未设置` → 返回特殊标识让前端提示设置密码
|
|
|
+
|
|
|
+#### 删除文件
|
|
|
+- `Admin.java` 实体类
|
|
|
+- `AdminMapper.java` Mapper 接口
|
|
|
+
|
|
|
+#### AdminController 调整
|
|
|
+- 移除 `@Resource AdminMapper` 注入
|
|
|
+- `guide/approve` 方法:删除同步创建/更新 admins 表的逻辑,审核通过直接更新 User 即可
|
|
|
+- 检查其他引用 `AdminMapper` 或 `Admin` 的地方并清理
|
|
|
+
|
|
|
+#### UserService 修复
|
|
|
+- `resetPassword` 方法(第1021行)当前使用 `xzyj_user_` 加密算法,改为统一的 `xzyj_salt_` + MD5
|
|
|
+
|
|
|
+### Module 3: 规划师首次密码创建
|
|
|
+
|
|
|
+#### 触发场景
|
|
|
+规划师审核通过后,登录 Web 管理端时:
|
|
|
+1. Web 登录页输入手机号 + 密码
|
|
|
+2. `AdminAuthController.loginByPassword` 查询 users 表
|
|
|
+3. 检测到 `role=teacher && (password==null || password=="")`
|
|
|
+4. 返回 `Result.error(400, "请先设置密码")` 附带 `needsSetup: true` 标识
|
|
|
+
|
|
|
+#### 小程序端设置密码
|
|
|
+1. 规划师在小程序 teacher-profile 页点击 "设置网页密码"
|
|
|
+2. 输入新密码 + 确认密码
|
|
|
+3. 调用后端 API `POST /api/auth/set-web-password`
|
|
|
+4. 后端执行:
|
|
|
+ - `UserService.setPassword(userId, newPassword)` — 用 `xzyj_salt_` + MD5 加密
|
|
|
+ - `UserService.updateUserStatus(userId, "actived")` — 设置状态为已激活
|
|
|
+5. 成功后规划师可用密码登录 Web 管理端
|
|
|
+
|
|
|
+#### 新增后端 API
|
|
|
+```java
|
|
|
+// AuthController 或 AdminAuthController 新增
|
|
|
+@PostMapping("/api/auth/set-web-password")
|
|
|
+public Result<Boolean> setWebPassword(@RequestAttribute("userId") Long userId,
|
|
|
+ @RequestBody Map<String, String> params) {
|
|
|
+ // 1. 校验密码强度 (6位以上)
|
|
|
+ // 2. 设置密码 (xzyj_salt_ + MD5)
|
|
|
+ // 3. 设置 status = actived
|
|
|
+ // 4. 返回成功
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Module 4: 规划师密码重置
|
|
|
+
|
|
|
+#### 小程序端修改密码
|
|
|
+1. 规划师在 teacher-profile 页 "修改网页密码"
|
|
|
+2. 输入旧密码 + 新密码 + 确认新密码
|
|
|
+3. 调用后端 API `POST /api/auth/reset-web-password`
|
|
|
+4. 后端执行:
|
|
|
+ - 校验旧密码是否正确
|
|
|
+ - 设置新密码(`xzyj_salt_` + MD5 加密)
|
|
|
+ - 状态保持不变
|
|
|
+
|
|
|
+#### 新增后端 API
|
|
|
+```java
|
|
|
+// AuthController 或 AdminAuthController 新增
|
|
|
+@PostMapping("/api/auth/reset-web-password")
|
|
|
+public Result<Boolean> resetWebPassword(@RequestAttribute("userId") Long userId,
|
|
|
+ @RequestBody Map<String, String> params) {
|
|
|
+ // 1. 校验旧密码
|
|
|
+ // 2. 设置新密码
|
|
|
+ // 3. 返回成功
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## 4. 加密算法统一
|
|
|
+
|
|
|
+**统一算法**: `DigestUtils.md5DigestAsHex(("xzyj_salt_" + password).getBytes(StandardCharsets.UTF_8))`
|
|
|
+
|
|
|
+| 位置 | 修改前 | 修改后 |
|
|
|
+|------|--------|--------|
|
|
|
+| AdminAuthController.encryptPassword (L271) | `xzyj_admin_salt_` + MD5 | `xzyj_salt_` + MD5 |
|
|
|
+| UserService.encryptPassword (L749) | `xzyj_salt_` + MD5 | ✅ 不变 |
|
|
|
+| UserService.resetPassword (L1021) | `xzyj_user_` + MD5 | `xzyj_salt_` + MD5 |
|
|
|
+
|
|
|
+## 5. 影响范围
|
|
|
+
|
|
|
+### 后端文件变更
|
|
|
+
|
|
|
+| 文件 | 变更类型 | 说明 |
|
|
|
+|------|----------|------|
|
|
|
+| `entity/User.java` | 修改 | 新增 username, status 字段 |
|
|
|
+| `entity/Admin.java` | 删除 | 废弃 |
|
|
|
+| `mapper/AdminMapper.java` | 删除 | 废弃 |
|
|
|
+| `controller/admin/AdminAuthController.java` | 重写 | UserMapper 替代 AdminMapper,统一加密 |
|
|
|
+| `controller/admin/AdminController.java` | 修改 | 移除 AdminMapper 引用,清理同步逻辑 |
|
|
|
+| `controller/auth/AuthController.java` | 修改 | 新增 set-web-password, reset-web-password 端点 |
|
|
|
+| `service/UserService.java` | 修改 | 修复 resetPassword 算法,新增 setStatus 方法 |
|
|
|
+| `config/DatabaseInitializer.java` | 修改 | 新增 username/status 迁移 + admins→users 数据迁移 |
|
|
|
+
|
|
|
+### 前端文件变更
|
|
|
+
|
|
|
+| 文件 | 变更类型 | 说明 |
|
|
|
+|------|----------|------|
|
|
|
+| `zxyj-frontend/pages/teacher/teacher-profile.vue` | 修改 | 拆分密码设置为首次设置和修改密码两个入口 |
|
|
|
+| `zxyj-frontend/utils/api.js` | 修改 | 新增 set-web-password, reset-web-password API |
|
|
|
+
|
|
|
+### Web端文件变更
|
|
|
+
|
|
|
+| 文件 | 变更类型 | 说明 |
|
|
|
+|------|----------|------|
|
|
|
+| `zxyj-web/src/views/Login.vue` | 无需修改 | AdminAuthController 端点不变(logic变化内部处理) |
|
|
|
+
|
|
|
+## 6. 安全考虑
|
|
|
+
|
|
|
+- 所有密码使用 MD5 + 固定 salt 传输(当前系统已有模式,暂不改 BCrypt 以保持兼容)
|
|
|
+- 小程序端不存储明文密码
|
|
|
+- Web 端密码传输使用 HTTPS(生产环境配置)
|
|
|
+
|
|
|
+## 7. 回滚方案
|
|
|
+
|
|
|
+- admins 表保留不删除,数据完整
|
|
|
+- 如果合并后出现问题,可停止使用 users 表的新字段
|
|
|
+- 钥匙管理器中有 DatabaseInitializer 中的迁移代码,重新部署会自动跳过
|