# 多用户管理功能 — 实现计划 ## 目标 当前项目只支持一个硬编码的 `admin` 用户。本计划将其升级为完整的**多用户管理体系**,支持管理员创建/编辑/删除普通用户、密码重置、用户列表展示、用户启用/禁用,以及权限分离(管理员 vs 普通用户)。 --- ## 实施步骤 ### 步骤 1:后端 — User 实体增加字段 **文件**: `backend/src/main/java/com/sshmanager/entity/User.java` | 新增字段 | 类型 | 说明 | |---------|------|------| | `role` | `String` | `"ROLE_ADMIN"` 或 `"ROLE_USER"`,默认 `"ROLE_USER"` | | `enabled` | `boolean` | 是否启用,默认 `true` | 同时为 `role` 和 `enabled` 添加数据库列映射。 --- ### 步骤 2:后端 — 创建 User 相关 DTO **新建文件**: | 文件 | 说明 | |------|------| | `backend/src/main/java/com/sshmanager/dto/UserDto.java` | 返回给前端的用户信息(不含密码) | | `backend/src/main/java/com/sshmanager/dto/CreateUserRequest.java` | 创建用户请求体 | | `backend/src/main/java/com/sshmanager/dto/UpdateUserRequest.java` | 更新用户请求体 | --- ### 步骤 3:后端 — 创建 UserService **新建文件**: `backend/src/main/java/com/sshmanager/service/UserService.java` 方法: - `listUsers()` — 列出所有用户(仅 admin) - `getUser(id)` — 获取单个用户 - `createUser(request)` — 创建用户,校验 username 唯一性 - `updateUser(id, request)` — 更新用户 displayName / role / enabled - `deleteUser(id)` — 删除用户(不能删除自己,不能删除最后一个 admin) - `resetPassword(id, newPassword)` — 管理员重置指定用户密码 --- ### 步骤 4:后端 — 创建 UserController **新建文件**: `backend/src/main/java/com/sshmanager/controller/UserController.java` REST API (`/api/users`): | 方法 | 路径 | 权限 | 说明 | |------|------|------|------| | GET | `/api/users` | ADMIN | 用户列表 | | GET | `/api/users/{id}` | ADMIN | 用户详情 | | POST | `/api/users` | ADMIN | 创建用户 | | PUT | `/api/users/{id}` | ADMIN | 更新用户 | | DELETE | `/api/users/{id}` | ADMIN | 删除用户 | | POST | `/api/users/{id}/reset-password` | ADMIN | 重置密码 | --- ### 步骤 5:后端 — Security / 权限改造 **文件**: - `CustomUserDetailsService.java` — 在 `UserDetails` 中赋予 `role` 对应的 `SimpleGrantedAuthority` - `SecurityConfig.java` — 添加 `antMatchers("/api/users/**").hasRole("ADMIN")` - `AuthController.java` — 修改 `/auth/me` 返回 `role` 字段 - `LoginResponse.java` — 添加 `role` 字段 - `DataInitializer.java` — admin 初始角色设为 `ROLE_ADMIN` **新建文件**: - `backend/src/main/java/com/sshmanager/security/AdminOnlyAspect.java` (可选,或直接在 Controller 里通过 Authentication 检查) --- ### 步骤 6:前端 — 类型和服务 **文件**: - `frontend/src/types.ts` — `LoginResponse` 和 `CurrentUser` 增加 `role: string` - `frontend/src/services/users.ts` — 用户 CRUD HTTP 服务 --- ### 步骤 7:前端 — 用户管理页面 **新建文件**: `frontend/src/pages/UserManagementPage.tsx` 功能: - 用户列表表格(用户名、显示名、角色、状态、创建时间) - 创建用户弹窗(用户名、密码、显示名、角色选择) - 编辑用户弹窗(修改显示名、角色、启用/禁用) - 删除用户(确认 + 不能删除自己) - 重置密码弹窗 --- ### 步骤 8:前端 — 路由 & 导航接入 **文件**: - `App.tsx` — 添加 `/users` 路由指向 `UserManagementPage` - `WorkspacePage.tsx` — 顶部导航栏增加"用户管理"按钮,仅当当前用户 `role === "ROLE_ADMIN"` 时显示 --- ## 数据流 ``` [UserManagementPage] --GET /api/users--> [UserController] --UserService--> [UserRepository] --> [DB] --POST /api/users--> --PUT /api/users/{id}--> --DELETE /api/users/{id}--> --POST /api/users/{id}/reset-password--> ``` 每个连接(Connection)已经通过 `userId` 与用户关联,同一用户仅能看到自己的连接。多用户后此逻辑保持不变。 --- ## 风险 & 注意事项 1. **不能删除最后一个 admin** — UserService 中 deleteUser 需检查 2. **不能禁用自己** — updateUser 如果自己禁用自己的 enabled=false 需拒绝 3. **密码重置后应强制改密** — 重置时设 `passwordChangedAt = Instant.EPOCH`,使 `isPasswordChangeRequired` 返回 true 4. **H2 数据库** — 重启后数据消失但 DataInitializer 会重建 admin;正式部署应考虑迁移到持久化数据库 --- ## 验证方式 1. 启动后端,`curl /api/users` 应返回 admin 用户 2. 用新用户登录验证数据隔离(自己只能看到自己的连接) 3. admin 删除最后一个 admin 用户应拒绝