Files
ssh-manager/multi-user-management-plan.md
liumangmang 1f1d1db65a feat: 多用户管理与公开注册功能
- 后端: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 适配
2026-05-28 09:13:27 +08:00

5.0 KiB
Raw Permalink Blame History

多用户管理功能 — 实现计划

目标

当前项目只支持一个硬编码的 admin 用户。本计划将其升级为完整的多用户管理体系,支持管理员创建/编辑/删除普通用户、密码重置、用户列表展示、用户启用/禁用,以及权限分离(管理员 vs 普通用户)。


实施步骤

步骤 1:后端 — User 实体增加字段

文件: backend/src/main/java/com/sshmanager/entity/User.java

新增字段 类型 说明
role String "ROLE_ADMIN""ROLE_USER",默认 "ROLE_USER"
enabled boolean 是否启用,默认 true

同时为 roleenabled 添加数据库列映射。


步骤 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.tsLoginResponseCurrentUser 增加 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 用户应拒绝