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 适配
5.0 KiB
5.0 KiB
多用户管理功能 — 实现计划
目标
当前项目只支持一个硬编码的 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 / enableddeleteUser(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对应的SimpleGrantedAuthoritySecurityConfig.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: stringfrontend/src/services/users.ts— 用户 CRUD HTTP 服务
步骤 7:前端 — 用户管理页面
新建文件: frontend/src/pages/UserManagementPage.tsx
功能:
- 用户列表表格(用户名、显示名、角色、状态、创建时间)
- 创建用户弹窗(用户名、密码、显示名、角色选择)
- 编辑用户弹窗(修改显示名、角色、启用/禁用)
- 删除用户(确认 + 不能删除自己)
- 重置密码弹窗
步骤 8:前端 — 路由 & 导航接入
文件:
App.tsx— 添加/users路由指向UserManagementPageWorkspacePage.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 与用户关联,同一用户仅能看到自己的连接。多用户后此逻辑保持不变。
风险 & 注意事项
- 不能删除最后一个 admin — UserService 中 deleteUser 需检查
- 不能禁用自己 — updateUser 如果自己禁用自己的 enabled=false 需拒绝
- 密码重置后应强制改密 — 重置时设
passwordChangedAt = Instant.EPOCH,使isPasswordChangeRequired返回 true - H2 数据库 — 重启后数据消失但 DataInitializer 会重建 admin;正式部署应考虑迁移到持久化数据库
验证方式
- 启动后端,
curl /api/users应返回 admin 用户 - 用新用户登录验证数据隔离(自己只能看到自己的连接)
- admin 删除最后一个 admin 用户应拒绝