1f1d1db65a
- 后端:User 实体新增 role/enabled 字段、UserController CRUD、UserService - 安全:SecurityConfig /api/users/** 要求 ROLE_ADMIN、JWT 过滤器检查账号状态 - 注册:POST /api/auth/register 公开注册,固定 ROLE_USER - 保护:删除/禁用/降级最后 admin 均拒绝,DataInitializer 含 backfill - 前端:用户管理页面、登录/注册切换、admin 专属导航入口 - 测试:UserServiceTest 19 个 + UserControllerTest 6 个 + AuthControllerTest 适配
139 lines
5.0 KiB
Markdown
139 lines
5.0 KiB
Markdown
# 多用户管理功能 — 实现计划
|
||
|
||
## 目标
|
||
|
||
当前项目只支持一个硬编码的 `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 用户应拒绝
|