library-picturebook-activity/docs/design/super-admin/tenant-auto-create-admin.md
aid 3c4100c231 feat: 创建租户时自动生成管理员账号、角色和权限
创建租户改为事务化一站式操作:自动复制 gdlib 权限模板 + 补充基础管理权限,
创建 tenant_admin 角色和管理员用户,支持自定义账号密码。
前端表单增加管理员输入区块,成功弹窗展示凭据并支持一键复制。
同步实现 menuIds 菜单分配(消除原 TODO)。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 18:48:34 +08:00

5.6 KiB
Raw Blame History

租户创建自动生成管理员账号 — 设计方案

所属端:超管端 状态:已完成 创建日期2026-04-02 最后更新2026-04-02


1. 背景与问题

超管端创建新租户(机构)后,需要手动到用户管理页面另行创建该租户的管理员账号、角色、权限,流程割裂且容易遗漏,导致新建的租户无法登录使用。

核心问题:

  • 创建租户与创建管理员是分离的两步操作,缺乏原子性
  • 新租户没有默认角色和权限,管理员账号无法正常使用
  • 菜单分配menuIds也未实现后端标记为 TODO

2. 现状分析

2.1 创建租户接口

  • POST /api/tenantsSysTenantServiceImpl.createTenant()
  • 仅创建 t_sys_tenant 记录,不创建用户、角色、权限、菜单关联
  • menuIds 参数存在但未处理TODO 注释)

2.2 初始化脚本的做法

backend/scripts/init-dev-tenants.tsNode 版,已移除)中,创建租户时会一并完成:

  1. 创建租户 → 2. 创建权限 → 3. 创建角色 → 4. 角色绑定权限 → 5. 创建 admin 用户 → 6. 用户绑定角色 → 7. 分配菜单

init.sql 中每个租户也都有对应的 admin 用户和角色。

2.3 涉及的数据表

表名 说明
t_sys_tenant 租户
t_sys_user 用户
t_sys_role 角色
t_sys_permission 权限(按租户隔离)
t_sys_user_role 用户-角色关联
t_sys_role_permission 角色-权限关联
t_sys_tenant_menu 租户-菜单关联

3. 设计方案

3.1 整体思路

创建租户时在同一事务中自动完成:创建租户 → 复制权限模板 → 创建管理员角色 → 创建管理员用户 → 绑定关联关系 → 分配菜单。接口返回租户信息 + 管理员凭据。

3.2 权限模板策略

  • 模板来源运行时从广东省图租户code=gdlibtenant_id=9复制权限该租户拥有 26 项业务权限,覆盖活动、报名、评审、作品、公告等核心模块
  • 补充基础管理权限:模板中缺少的 7 项基础权限自动补充:
    • user:updateuser:delete — 用户管理
    • role:createrole:updaterole:deleterole:assign — 角色管理
    • permission:read — 权限查看
  • 新租户最终获得 33 项权限26 模板 + 7 补充)

3.3 前端页面设计

创建表单改动

  • 基本信息 Tab 增加「管理员账号」区块(用分割线分隔)
  • 新增两个输入框:管理员账号(默认 admin、管理员密码默认 admin@{编码}
  • 仅新建时显示,编辑时隐藏

成功弹窗改动

  • 原先:提示"创建成功"+ 跳转用户管理页按钮
  • 现在:展示管理员账号、初始密码、登录地址
  • 新增「复制账号信息」按钮,一键复制全部信息到剪贴板

3.4 后端改动

CreateTenantDto — 新增字段:

  • adminUsernameString可选默认 "admin"
  • adminPasswordString可选默认 "admin@{tenantCode}"

ISysTenantService.createTenant() — 返回值改为 Map<String, Object>

SysTenantServiceImpl.createTenant() — 核心改动,事务内完成 7 步:

  1. 创建租户记录
  2. copyTemplatePermissions() — 复制 gdlib 权限 + 补充基础权限
  3. 创建 tenant_admin 角色
  4. 批量绑定角色-权限
  5. 创建管理员用户(密码 BCrypt 加密)
  6. 绑定用户-角色
  7. 处理 menuIds 菜单分配

新增私有方法 copyTemplatePermissions(Long newTenantId)

  • 查询 gdlib 租户的全部权限,逐条复制(替换 tenantId
  • 对比已有权限编码,补充缺失的基础管理权限

SysTenantServiceImpl.updateTenant() — 同步实现 menuIds 更新(先删后增)

SysTenantController.create() — 返回类型从 Result<SysTenant> 改为 Result<Map<String, Object>>

3.5 接口响应格式

{
  "code": 200,
  "data": {
    "tenant": {
      "id": 13,
      "name": "测试图书馆",
      "code": "test-lib",
      "tenantType": "library",
      ...
    },
    "admin": {
      "username": "libadmin",
      "password": "Lib@2026",
      "userId": 32,
      "nickname": "测试图书馆管理员"
    }
  }
}

3.6 前端改动

src/api/tenants.ts

  • CreateTenantForm 新增 adminUsernameadminPassword
  • 新增 CreateTenantResult 接口
  • createTenant() 返回类型改为 CreateTenantResult

src/views/system/tenants/Index.vue

  • 表单 reactive 新增 adminUsernameadminPassword
  • 模板增加管理员输入区块
  • 成功弹窗展示管理员信息卡片 + 复制按钮
  • 移除 useRouteruseAuthStore 无用依赖

4. 改动范围

后端Java

操作 文件
修改 modules/sys/dto/CreateTenantDto.java
修改 modules/sys/service/ISysTenantService.java
修改 modules/sys/service/impl/SysTenantServiceImpl.java
修改 modules/sys/controller/SysTenantController.java

前端

操作 文件
修改 src/api/tenants.ts
修改 src/views/system/tenants/Index.vue

5. 实施记录

2026-04-02 — 初版实现

  • 完成后端事务化创建租户 + 管理员 + 角色 + 权限 + 菜单分配
  • 权限模板使用 gdlib 租户26项+ 7项基础管理权限补充
  • 前端表单增加管理员账号/密码输入,成功弹窗展示凭据信息
  • 测试验证:创建租户 → 管理员登录成功 → 获得 97 项权限(含 gdlib 完整业务权限 + 补充权限)
  • 同步实现了 updateTenant 的 menuIds 更新(消除 TODO