pangu-user-platform/docs/05-模块技术方案/应用管理模块技术方案_v1.0.md

49 KiB
Raw Blame History

盘古用户平台 - 应用管理模块技术方案


文档信息 内容
文档版本 V1.0
项目名称 盘古用户平台Pangu User Platform
模块名称 应用管理模块
编写团队 湖北新华业务中台研发团队
创建日期 2026-01-31
审核状态 待评审

修订记录

版本 日期 修订人 修订内容
V1.0 2026-01-31 湖北新华业务中台研发团队 初稿

目录

  1. 模块概述
  2. 需求分析
  3. 系统设计
  4. 前端技术方案
  5. 后端技术方案
  6. 数据库设计
  7. 接口设计
  8. 开发计划
  9. 测试方案
  10. 风险评估

1. 模块概述

1.1 模块定位

应用管理模块是盘古用户平台的核心模块之一负责管理接入平台的第三方应用控制API接口访问权限。通过该模块超级管理员可以创建应用、分配接口权限、管理应用密钥实现对外开放API的安全访问控制。

1.2 核心价值

价值点 描述
统一接入管理 对所有第三方应用进行统一注册和管理
细粒度权限控制 精确控制每个应用可访问的API接口
安全认证机制 通过AppId+AppSecret签名机制保障接口安全
密钥生命周期管理 支持密钥重置,确保安全风险可控

1.3 模块边界

┌─────────────────────────────────────────────────────────────┐
│                      应用管理模块                            │
├─────────────────────────────────────────────────────────────┤
│  ┌───────────────┐  ┌───────────────┐  ┌───────────────┐   │
│  │   应用CRUD    │  │   接口授权    │  │   密钥管理    │   │
│  │  - 新增应用   │  │  - 接口勾选   │  │  - 自动生成   │   │
│  │  - 编辑应用   │  │  - 权限存储   │  │  - 重置密钥   │   │
│  │  - 删除应用   │  │  - 权限校验   │  │  - 安全提示   │   │
│  │  - 查询列表   │  │               │  │               │   │
│  └───────────────┘  └───────────────┘  └───────────────┘   │
│                              │                              │
│                              ▼                              │
│                    ┌───────────────┐                        │
│                    │  开放API网关  │                        │
│                    │  - 签名验证   │                        │
│                    │  - 权限校验   │                        │
│                    │  - 请求转发   │                        │
│                    └───────────────┘                        │
└─────────────────────────────────────────────────────────────┘

2. 需求分析

2.1 功能需求

2.1.1 功能清单

功能编号 功能名称 功能描述 优先级 状态
APP-001 应用列表查询 按应用名称、编码、状态筛选查询 P0 待开发
APP-002 新增应用 创建新应用,自动生成应用编码和密钥 P0 待开发
APP-003 编辑应用 修改应用信息和接口授权 P0 待开发
APP-004 删除应用 删除应用及其授权信息 P1 待开发
APP-005 重置密钥 重新生成应用密钥 P0 待开发
APP-006 接口授权 配置应用可访问的API接口 P0 待开发
APP-007 禁用/启用应用 控制应用访问权限 P0 待开发

2.1.2 业务规则

规则编号 规则描述 验证方式
APP-R01 应用编码由系统自动生成格式YY + 6位数字序号 后端生成
APP-R02 应用密钥由系统自动生成32位随机字符串 后端生成
APP-R03 重置密钥后,旧密钥立即失效 后端处理
APP-R04 重置密钥后需弹窗显示新密钥并提供复制功能 前端展示
APP-R05 删除应用需popconfirm二次确认 前端交互
APP-R06 禁用应用后该应用无法调用任何API接口 后端拦截
APP-R07 接口授权采用勾选方式,可多选 前端交互
APP-R08 应用名称不能重复 后端校验

2.2 非功能需求

需求类型 需求描述 指标
性能 应用列表查询响应时间 ≤ 500ms
性能 接口授权校验响应时间 ≤ 50ms
安全 密钥加密存储 AES加密
安全 接口签名验证 MD5签名
安全 防重放攻击 时间戳校验5分钟内有效
可用性 权限变更实时生效 无需重启服务

2.3 用户角色

角色 权限范围
超级管理员 可查看所有应用,可新增/编辑/删除应用,可进行接口授权,可重置密钥
分公司用户 无权限
学校用户 无权限

3. 系统设计

3.1 整体架构

┌─────────────────────────────────────────────────────────────────────┐
│                           前端层                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                 应用管理页面 (Vue 3 + Element Plus)           │   │
│  │  - 列表页 (index.vue)                                         │   │
│  │  - 新增/编辑弹窗 (AppDialog.vue)                              │   │
│  │  - 密钥展示弹窗 (SecretDialog.vue)                            │   │
│  └─────────────────────────────────────────────────────────────┘   │
└────────────────────────────────┬────────────────────────────────────┘
                                 │ HTTP/HTTPS
                                 ▼
┌─────────────────────────────────────────────────────────────────────┐
│                          后端服务层                                  │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │              应用管理服务 (Spring Boot)                       │   │
│  │  - ApplicationController                                       │   │
│  │  - ApplicationService                                          │   │
│  │  - ApplicationMapper                                           │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                      │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │              开放API网关                                       │   │
│  │  - ApiAuthInterceptor (签名验证)                              │   │
│  │  - ApiPermissionFilter (权限校验)                             │   │
│  └─────────────────────────────────────────────────────────────┘   │
└────────────────────────────────┬────────────────────────────────────┘
                                 │
                                 ▼
┌─────────────────────────────────────────────────────────────────────┐
│                          数据层                                      │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │
│  │ pg_application│  │ pg_app_api   │  │ pg_api_dict  │              │
│  │   应用表      │  │ 应用接口授权  │  │  接口字典    │              │
│  └──────────────┘  └──────────────┘  └──────────────┘              │
│                                                                      │
│  ┌──────────────┐                                                   │
│  │    Redis     │ ← 缓存应用授权信息,提升验证性能                   │
│  └──────────────┘                                                   │
└─────────────────────────────────────────────────────────────────────┘

3.2 数据流设计

3.2.1 应用创建流程

┌───────────┐      ┌───────────┐      ┌───────────┐      ┌───────────┐
│   前端     │      │ Controller │      │  Service  │      │   MySQL   │
└─────┬─────┘      └─────┬─────┘      └─────┬─────┘      └─────┬─────┘
      │                  │                  │                  │
      │  POST /api/application             │                  │
      │──────────────────►                 │                  │
      │                  │                  │                  │
      │                  │  insertApplication                 │
      │                  │──────────────────►                 │
      │                  │                  │                  │
      │                  │                  │ 1.生成应用编码   │
      │                  │                  │ 2.生成密钥       │
      │                  │                  │ 3.加密存储       │
      │                  │                  │──────────────────►
      │                  │                  │                  │
      │                  │                  │ 4.保存接口授权   │
      │                  │                  │──────────────────►
      │                  │                  │                  │
      │  返回新密钥(仅新增时)             │                  │
      │◄──────────────────                 │                  │
      │                  │                  │                  │

3.2.2 开放API调用流程

┌───────────┐      ┌───────────┐      ┌───────────┐      ┌───────────┐
│ 第三方应用 │      │ API网关    │      │   Redis   │      │   业务    │
└─────┬─────┘      └─────┬─────┘      └─────┬─────┘      └─────┬─────┘
      │                  │                  │                  │
      │  GET /open/xxx   │                  │                  │
      │  Header: X-App-Id, X-Timestamp, X-Sign                │
      │──────────────────►                 │                  │
      │                  │                  │                  │
      │                  │  1.验证时间戳   │                  │
      │                  │  2.查询应用信息 │                  │
      │                  │──────────────────►                 │
      │                  │◄──────────────────                 │
      │                  │                  │                  │
      │                  │  3.验证签名     │                  │
      │                  │  4.检查应用状态 │                  │
      │                  │  5.检查接口权限 │                  │
      │                  │                  │                  │
      │                  │                  │  转发请求       │
      │                  │─────────────────────────────────────►
      │                  │                  │                  │
      │  返回业务数据   │                  │                  │
      │◄──────────────────────────────────────────────────────│
      │                  │                  │                  │

4. 前端技术方案

4.1 技术栈

技术 版本 用途
Vue 3.x 前端框架
Element Plus 2.x UI组件库
Axios 1.x HTTP客户端
Pinia 2.x 状态管理

4.2 目录结构

pangu-ui/src/
├── api/
│   └── application.js          # 应用管理API封装
├── views/
│   └── application/
│       ├── index.vue           # 应用列表页
│       └── components/
│           ├── AppDialog.vue   # 新增/编辑弹窗
│           └── SecretDialog.vue # 密钥展示弹窗
└── mock/
    └── application.js          # Mock数据开发阶段

4.3 页面设计

4.3.1 应用列表页 (index.vue)

页面布局

┌─────────────────────────────────────────────────────────────────┐
│ 搜索区域                                                         │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ ┌────┐ ┌────┐  │
│ │ 应用名称     │ │ 应用编码     │ │ 状态 ▼   │ │搜索│ │重置│  │
│ └──────────────┘ └──────────────┘ └──────────┘ └────┘ └────┘  │
├─────────────────────────────────────────────────────────────────┤
│ [+ 新增]                                                         │
├─────────────────────────────────────────────────────────────────┤
│ 表格区域                                                         │
│ ┌──────┬──────────┬────────────────────┬────────┬──────┬─────┐│
│ │应用名│ 应用编码  │ 授权接口            │ 状态   │ 创建 │操作 ││
│ ├──────┼──────────┼────────────────────┼────────┼──────┼─────┤│
│ │智慧  │ YY000001 │ [学校] [年级] [+3] │ ● 正常 │01-01 │编辑 ││
│ │校园  │          │                    │        │admin │重置 ││
│ │      │          │                    │        │      │删除 ││
│ └──────┴──────────┴────────────────────┴────────┴──────┴─────┘│
├─────────────────────────────────────────────────────────────────┤
│                                     共 20 条 [<] 1 2 3 ... [>]  │
└─────────────────────────────────────────────────────────────────┘

核心代码结构

<template>
  <div class="app-container">
    <!-- 搜索区域 -->
    <el-card shadow="never" class="search-wrapper">
      <el-form :model="queryParams" :inline="true">
        <el-form-item label="应用名称">
          <el-input v-model="queryParams.appName" placeholder="请输入" clearable />
        </el-form-item>
        <el-form-item label="应用编码">
          <el-input v-model="queryParams.appCode" placeholder="请输入" clearable />
        </el-form-item>
        <el-form-item label="状态">
          <el-select v-model="queryParams.status" placeholder="全部" clearable>
            <el-option label="正常" value="0" />
            <el-option label="停用" value="1" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleQuery">搜索</el-button>
          <el-button @click="resetQuery">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <!-- 表格区域 -->
    <el-card shadow="never">
      <el-button type="primary" @click="handleAdd">新增</el-button>
      <el-table :data="tableData" border stripe>
        <el-table-column prop="appName" label="应用名称" />
        <el-table-column prop="appCode" label="应用编码" />
        <el-table-column prop="apis" label="授权接口">
          <template #default="{ row }">
            <el-tag v-for="api in row.apis?.slice(0, 3)" :key="api" size="small">
              {{ api }}
            </el-tag>
            <el-tag v-if="row.apis?.length > 3" type="info">+{{ row.apis.length - 3 }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="status" label="状态">
          <template #default="{ row }">
            <el-tag :type="row.status === '0' ? 'success' : 'danger'">
              {{ row.status === '0' ? '正常' : '停用' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="创建时间" />
        <el-table-column label="操作" fixed="right">
          <template #default="{ row }">
            <el-button link @click="handleEdit(row)">编辑</el-button>
            <el-button link @click="handleResetSecret(row)">重置密钥</el-button>
            <el-popconfirm title="确定删除?" @confirm="handleDelete(row)">
              <template #reference>
                <el-button link type="danger">删除</el-button>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination v-model:current-page="queryParams.pageNum" :total="total" />
    </el-card>

    <!-- 弹窗组件 -->
    <AppDialog ref="appDialogRef" @success="handleQuery" />
    <SecretDialog ref="secretDialogRef" />
  </div>
</template>

4.3.2 新增/编辑弹窗 (AppDialog.vue)

表单布局

┌─────────────────────────────────────────────────────────────────┐
│ 新增应用 / 编辑应用                                        [X] │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   应用名称*   [________________________]                        │
│                                                                  │
│   应用编码    [保存后自动生成___________]  (只读)             │
│                                                                  │
│   应用描述    [________________________]                        │
│               [________________________]                        │
│               [________________________]                        │
│                                                                  │
│   联系人      [________________________]                        │
│                                                                  │
│   联系电话    [________________________]                        │
│                                                                  │
│   状态        [●] 正常  [○] 停用                                │
│                                                                  │
│   接口授权    [✓] 查询学生信息                                  │
│               [✓] 查询学校信息                                  │
│               [✓] 查询年级信息                                  │
│               [ ] 查询班级信息                                  │
│               [ ] 查询会员信息                                  │
│               [ ] 查询区域树                                    │
│                                                                  │
├─────────────────────────────────────────────────────────────────┤
│                                        [取消]  [确定]           │
└─────────────────────────────────────────────────────────────────┘

表单字段说明

字段 类型 必填 校验规则 说明
appName 文本 最大100字符 应用名称
appCode 文本 - 只读 系统自动生成
description 文本域 - 最大500字符 应用描述
contactPerson 文本 - 最大50字符 联系人
contactPhone 文本 - 手机号格式 联系电话
status 开关 - 0正常/1停用
apiCodes 复选框组 - - 授权的接口编码列表

4.3.3 密钥展示弹窗 (SecretDialog.vue)

弹窗布局

┌─────────────────────────────────────────────────────────────────┐
│ 应用密钥                                                   [X] │
├─────────────────────────────────────────────────────────────────┤
│  ⚠️ 请妥善保管密钥,密钥重置后旧密钥将立即失效                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   应用名称    AI智慧平台                                        │
│                                                                  │
│   应用编码    YY000001                                          │
│                                                                  │
│   应用密钥    [a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6] [复制]       │
│                                                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                      [关闭]     │
└─────────────────────────────────────────────────────────────────┘

4.4 API接口封装

/**
 * 应用管理API接口
 * @author 湖北新华业务中台研发团队
 */
import request from '@/utils/request'

// 获取应用列表
export function listApplication(params) {
  return request.get('/api/application/list', { params })
}

// 获取应用详情
export function getApplication(appId) {
  return request.get(`/api/application/${appId}`)
}

// 新增应用
export function addApplication(data) {
  return request.post('/api/application', data)
}

// 修改应用
export function updateApplication(data) {
  return request.put('/api/application', data)
}

// 删除应用
export function deleteApplication(appId) {
  return request.delete(`/api/application/${appId}`)
}

// 重置密钥
export function resetAppSecret(appId) {
  return request.put(`/api/application/resetSecret/${appId}`)
}

// 获取API接口列表用于授权选择
export function getApiList() {
  return request.get('/api/application/apiList')
}

4.5 前端开发规范

规范项 说明
组件命名 大驼峰,如 AppDialog.vue
方法命名 小驼峰,如 handleQueryhandleEdit
事件处理 handle 开头,如 handleSubmit
API请求 统一使用 @/utils/request 封装
表单验证 使用 Element Plus 的 Form 组件校验
错误处理 统一使用 ElMessage 提示

5. 后端技术方案

5.1 技术栈

技术 版本 用途
Spring Boot 3.3.x 应用框架
Spring Security 6.x 安全框架
MyBatis Plus 3.5.x ORM框架
Redis 7.x 缓存
Hutool 5.x 工具库
JDK 17+ 运行环境

5.2 模块结构

pangu-admin/
├── controller/
│   └── ApplicationController.java    # 应用管理控制器
├── service/
│   ├── IApplicationService.java      # 应用服务接口
│   └── impl/
│       └── ApplicationServiceImpl.java
├── mapper/
│   ├── ApplicationMapper.java        # 应用Mapper
│   └── AppApiMapper.java             # 应用接口授权Mapper
├── domain/
│   ├── entity/
│   │   ├── Application.java          # 应用实体
│   │   ├── AppApi.java               # 应用接口授权实体
│   │   └── ApiDict.java              # 接口字典实体
│   ├── vo/
│   │   └── ApplicationVO.java        # 应用视图对象
│   └── dto/
│       └── ApplicationDTO.java       # 应用传输对象
└── util/
    └── SecretGenerator.java          # 密钥生成工具

pangu-open/
├── controller/
│   └── OpenApiController.java        # 开放API控制器
├── interceptor/
│   └── ApiAuthInterceptor.java       # API认证拦截器
└── service/
    └── ApiAuthService.java           # API认证服务

5.3 核心类设计

5.3.1 实体类 (Application.java)

/**
 * 应用实体
 * @author 湖北新华业务中台研发团队
 */
@Data
@TableName("pg_application")
public class Application extends BaseEntity {
    
    /** 应用ID */
    @TableId(type = IdType.AUTO)
    private Long appId;
    
    /** 应用编码 */
    private String appCode;
    
    /** 应用名称 */
    private String appName;
    
    /** 应用密钥(加密存储) */
    private String appSecret;
    
    /** 应用描述 */
    private String appDesc;
    
    /** 联系人 */
    private String contactPerson;
    
    /** 联系电话 */
    private String contactPhone;
    
    /** 状态0正常 1停用 */
    private String status;
    
    /** 删除标志 */
    @TableLogic
    private String delFlag;
}

5.3.2 服务接口 (IApplicationService.java)

/**
 * 应用管理服务接口
 * @author 湖北新华业务中台研发团队
 */
public interface IApplicationService {
    
    /**
     * 查询应用列表
     */
    List<ApplicationVO> selectApplicationList(ApplicationDTO dto);
    
    /**
     * 查询应用详情
     */
    ApplicationVO selectApplicationById(Long appId);
    
    /**
     * 新增应用
     * @return 返回应用编码和密钥
     */
    Map<String, String> insertApplication(ApplicationDTO dto);
    
    /**
     * 修改应用
     */
    int updateApplication(ApplicationDTO dto);
    
    /**
     * 删除应用
     */
    int deleteApplicationById(Long appId);
    
    /**
     * 重置密钥
     * @return 返回新密钥
     */
    String resetAppSecret(Long appId);
    
    /**
     * 根据应用编码查询应用信息用于API认证
     */
    Application selectByAppCode(String appCode);
    
    /**
     * 检查应用是否有接口权限
     */
    boolean checkApiPermission(String appCode, String apiPath);
}

5.3.3 控制器 (ApplicationController.java)

/**
 * 应用管理控制器
 * @author 湖北新华业务中台研发团队
 */
@RestController
@RequestMapping("/api/application")
@PreAuthorize("hasRole('admin')")  // 仅超级管理员可访问
public class ApplicationController extends BaseController {
    
    @Autowired
    private IApplicationService applicationService;
    
    /**
     * 查询应用列表
     */
    @GetMapping("/list")
    public TableDataInfo list(ApplicationDTO dto) {
        startPage();
        List<ApplicationVO> list = applicationService.selectApplicationList(dto);
        return getDataTable(list);
    }
    
    /**
     * 获取应用详情
     */
    @GetMapping("/{appId}")
    public AjaxResult getInfo(@PathVariable Long appId) {
        return AjaxResult.success(applicationService.selectApplicationById(appId));
    }
    
    /**
     * 新增应用
     */
    @PostMapping
    @Log(title = "应用管理", businessType = BusinessType.INSERT)
    public AjaxResult add(@Validated @RequestBody ApplicationDTO dto) {
        Map<String, String> result = applicationService.insertApplication(dto);
        return AjaxResult.success(result);
    }
    
    /**
     * 修改应用
     */
    @PutMapping
    @Log(title = "应用管理", businessType = BusinessType.UPDATE)
    public AjaxResult edit(@Validated @RequestBody ApplicationDTO dto) {
        return toAjax(applicationService.updateApplication(dto));
    }
    
    /**
     * 删除应用
     */
    @DeleteMapping("/{appId}")
    @Log(title = "应用管理", businessType = BusinessType.DELETE)
    public AjaxResult remove(@PathVariable Long appId) {
        return toAjax(applicationService.deleteApplicationById(appId));
    }
    
    /**
     * 重置密钥
     */
    @PutMapping("/resetSecret/{appId}")
    @Log(title = "应用管理", businessType = BusinessType.UPDATE)
    public AjaxResult resetSecret(@PathVariable Long appId) {
        String newSecret = applicationService.resetAppSecret(appId);
        return AjaxResult.success("重置成功", Map.of("appSecret", newSecret));
    }
    
    /**
     * 获取API接口列表
     */
    @GetMapping("/apiList")
    public AjaxResult apiList() {
        return AjaxResult.success(applicationService.selectApiDictList());
    }
}

5.4 核心算法

5.4.1 应用编码生成

/**
 * 生成应用编码
 * 格式YY + 6位序号从000001开始
 */
public String generateAppCode() {
    // 获取当前最大序号
    String maxCode = applicationMapper.selectMaxAppCode();
    int nextSeq = 1;
    if (StringUtils.isNotBlank(maxCode)) {
        nextSeq = Integer.parseInt(maxCode.substring(2)) + 1;
    }
    return String.format("YY%06d", nextSeq);
}

5.4.2 密钥生成

/**
 * 生成32位随机密钥
 */
public String generateAppSecret() {
    return RandomUtil.randomString(32);
}

5.4.3 签名验证

/**
 * 验证API请求签名
 */
public boolean verifySign(HttpServletRequest request) {
    String appId = request.getHeader("X-App-Id");
    String timestamp = request.getHeader("X-Timestamp");
    String sign = request.getHeader("X-Sign");
    
    // 1. 验证时间戳5分钟内有效
    long reqTime = Long.parseLong(timestamp);
    if (Math.abs(System.currentTimeMillis() - reqTime) > 5 * 60 * 1000) {
        throw new ApiException("请求已过期");
    }
    
    // 2. 获取应用密钥
    Application app = applicationService.selectByAppCode(appId);
    if (app == null || "1".equals(app.getStatus())) {
        throw new ApiException("应用不存在或已禁用");
    }
    
    // 3. 构建签名字符串
    String signStr = buildSignString(request, app.getAppSecret());
    
    // 4. 验证签名
    String expectedSign = DigestUtils.md5Hex(signStr).toUpperCase();
    return expectedSign.equals(sign);
}

/**
 * 构建签名字符串
 * 将请求参数按ASCII排序后拼接末尾追加appSecret
 */
private String buildSignString(HttpServletRequest request, String appSecret) {
    Map<String, String> params = new TreeMap<>();
    request.getParameterMap().forEach((key, values) -> {
        if (values.length > 0) {
            params.put(key, values[0]);
        }
    });
    
    StringBuilder sb = new StringBuilder();
    params.forEach((key, value) -> {
        if (sb.length() > 0) sb.append("&");
        sb.append(key).append("=").append(value);
    });
    sb.append("&appSecret=").append(appSecret);
    
    return sb.toString();
}

5.5 缓存设计

缓存KEY 过期时间 说明
app:info:{appCode} 30分钟 应用基本信息
app:apis:{appCode} 30分钟 应用授权的接口列表
/**
 * 清除应用缓存
 * 在修改、删除、重置密钥时调用
 */
public void clearAppCache(String appCode) {
    redisCache.deleteObject("app:info:" + appCode);
    redisCache.deleteObject("app:apis:" + appCode);
}

6. 数据库设计

6.1 表结构

6.1.1 应用表 (pg_application)

CREATE TABLE `pg_application` (
  `app_id` bigint NOT NULL AUTO_INCREMENT COMMENT '应用ID',
  `app_code` varchar(32) NOT NULL COMMENT '应用编码',
  `app_name` varchar(100) NOT NULL COMMENT '应用名称',
  `app_secret` varchar(64) NOT NULL COMMENT '应用密钥',
  `app_desc` varchar(500) DEFAULT NULL COMMENT '应用描述',
  `contact_person` varchar(50) DEFAULT NULL COMMENT '联系人',
  `contact_phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
  `status` char(1) DEFAULT '0' COMMENT '状态0正常 1停用',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `del_flag` char(1) DEFAULT '0' COMMENT '删除标志0存在 1删除',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`app_id`),
  UNIQUE KEY `uk_app_code` (`app_code`)
) ENGINE=InnoDB COMMENT='应用表';

6.1.2 应用接口授权表 (pg_app_api)

CREATE TABLE `pg_app_api` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `app_id` bigint NOT NULL COMMENT '应用ID',
  `api_code` varchar(100) NOT NULL COMMENT '接口编码',
  `api_name` varchar(100) DEFAULT NULL COMMENT '接口名称',
  `api_path` varchar(200) NOT NULL COMMENT '接口路径',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_app_api` (`app_id`, `api_code`),
  KEY `idx_app_id` (`app_id`)
) ENGINE=InnoDB COMMENT='应用接口授权表';

6.1.3 API接口字典表 (pg_api_dict)

CREATE TABLE `pg_api_dict` (
  `api_id` bigint NOT NULL AUTO_INCREMENT COMMENT '接口ID',
  `api_code` varchar(100) NOT NULL COMMENT '接口编码',
  `api_name` varchar(100) NOT NULL COMMENT '接口名称',
  `api_path` varchar(200) NOT NULL COMMENT '接口路径',
  `api_method` varchar(10) DEFAULT 'GET' COMMENT '请求方法',
  `api_desc` varchar(500) DEFAULT NULL COMMENT '接口描述',
  `order_num` int DEFAULT 0 COMMENT '显示顺序',
  `status` char(1) DEFAULT '0' COMMENT '状态0正常 1停用',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`api_id`),
  UNIQUE KEY `uk_api_code` (`api_code`)
) ENGINE=InnoDB COMMENT='API接口字典表';

6.2 初始化数据

-- API接口字典数据
INSERT INTO pg_api_dict (api_id, api_code, api_name, api_path, api_method, api_desc, order_num) VALUES
(1, 'STUDENT_LIST', '查询学生信息', '/open/student/list', 'GET', '获取学生列表', 1),
(2, 'SCHOOL_LIST', '查询学校信息', '/open/school/list', 'GET', '获取学校列表', 2),
(3, 'GRADE_LIST', '查询年级信息', '/open/grade/list', 'GET', '获取年级列表', 3),
(4, 'CLASS_LIST', '查询班级信息', '/open/class/list', 'GET', '获取班级列表', 4),
(5, 'MEMBER_LIST', '查询会员信息', '/open/member/list', 'GET', '获取会员列表', 5),
(6, 'REGION_TREE', '查询区域树', '/open/region/tree', 'GET', '获取区域树形结构', 6);

-- 示例应用数据
INSERT INTO pg_application (app_id, app_code, app_name, app_secret, app_desc, status, create_time) VALUES
(1, 'YY000001', 'AI智慧平台', 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6', 'AI智慧教育平台接入', '0', NOW());

-- 示例应用接口授权
INSERT INTO pg_app_api (id, app_id, api_code, api_name, api_path, create_time) VALUES
(1, 1, 'SCHOOL_LIST', '查询学校信息', '/open/school/list', NOW()),
(2, 1, 'GRADE_LIST', '查询年级信息', '/open/grade/list', NOW()),
(3, 1, 'CLASS_LIST', '查询班级信息', '/open/class/list', NOW());

6.3 索引设计

表名 索引名 索引字段 说明
pg_application uk_app_code app_code 应用编码唯一
pg_app_api uk_app_api app_id, api_code 应用接口唯一
pg_app_api idx_app_id app_id 按应用查询
pg_api_dict uk_api_code api_code 接口编码唯一

7. 接口设计

7.1 管理端接口

7.1.1 查询应用列表

项目 内容
接口地址 GET /api/application/list
请求参数 appName, appCode, status, pageNum, pageSize
响应格式 TableDataInfo分页格式

7.1.2 获取应用详情

项目 内容
接口地址 GET /api/application/{appId}
请求参数 appId路径参数
响应格式 AjaxResult

7.1.3 新增应用

项目 内容
接口地址 POST /api/application
请求体 ApplicationDTO
响应格式 AjaxResult包含appCode和appSecret

请求示例

{
    "appName": "AI智慧平台",
    "appDesc": "AI教育智慧平台",
    "contactPerson": "张经理",
    "contactPhone": "13812345678",
    "status": "0",
    "apiCodes": ["STUDENT_LIST", "SCHOOL_LIST", "GRADE_LIST"]
}

响应示例

{
    "code": 200,
    "msg": "新增成功",
    "data": {
        "appCode": "YY000002",
        "appSecret": "x1y2z3a4b5c6d7e8f9g0h1i2j3k4l5m6"
    }
}

7.1.4 修改应用

项目 内容
接口地址 PUT /api/application
请求体 ApplicationDTO包含appId
响应格式 AjaxResult

7.1.5 删除应用

项目 内容
接口地址 DELETE /api/application/{appId}
请求参数 appId路径参数
响应格式 AjaxResult

7.1.6 重置密钥

项目 内容
接口地址 PUT /api/application/resetSecret/{appId}
请求参数 appId路径参数
响应格式 AjaxResult包含新的appSecret

响应示例

{
    "code": 200,
    "msg": "重置成功",
    "data": {
        "appSecret": "n1e2w3s4e5c6r7e8t9k0e1y2v3a4l5u6"
    }
}

7.1.7 获取API接口列表

项目 内容
接口地址 GET /api/application/apiList
请求参数
响应格式 AjaxResult

响应示例

{
    "code": 200,
    "msg": "查询成功",
    "data": [
        { "apiCode": "STUDENT_LIST", "apiName": "查询学生信息", "apiPath": "/open/student/list" },
        { "apiCode": "SCHOOL_LIST", "apiName": "查询学校信息", "apiPath": "/open/school/list" },
        { "apiCode": "GRADE_LIST", "apiName": "查询年级信息", "apiPath": "/open/grade/list" },
        { "apiCode": "CLASS_LIST", "apiName": "查询班级信息", "apiPath": "/open/class/list" },
        { "apiCode": "MEMBER_LIST", "apiName": "查询会员信息", "apiPath": "/open/member/list" },
        { "apiCode": "REGION_TREE", "apiName": "查询区域树", "apiPath": "/open/region/tree" }
    ]
}

7.2 开放API接口

7.2.1 签名规则

请求头

Header 必填 说明
X-App-Id 应用编码
X-Timestamp 时间戳(毫秒)
X-Sign 签名

签名算法

1. 将所有请求参数按参数名ASCII升序排序
2. 拼接成 key1=value1&key2=value2 格式
3. 末尾追加 &appSecret=xxx
4. 对整个字符串进行MD5加密32位大写

Java签名示例

public String generateSign(Map<String, String> params, String appSecret) {
    // 1. 参数排序
    Map<String, String> sortedParams = new TreeMap<>(params);
    
    // 2. 拼接字符串
    StringBuilder sb = new StringBuilder();
    sortedParams.forEach((key, value) -> {
        if (sb.length() > 0) sb.append("&");
        sb.append(key).append("=").append(value);
    });
    sb.append("&appSecret=").append(appSecret);
    
    // 3. MD5加密
    return DigestUtils.md5Hex(sb.toString()).toUpperCase();
}

8. 开发计划

8.1 阶段划分

阶段 内容 交付物
阶段一:设计评审 技术方案评审、接口设计评审 评审通过的技术方案
阶段二:后端开发 数据库表创建、后端接口开发 可调试的后端API
阶段三:前端开发 前端页面开发、接口联调 可运行的前端页面
阶段四:联调测试 前后端联调、功能测试 测试报告
阶段五:验收上线 用户验收、部署上线 上线报告

8.2 开发任务清单

8.2.1 后端任务

序号 任务 优先级 依赖
1 创建数据库表 P0 -
2 实体类和Mapper开发 P0 1
3 Service层开发 P0 2
4 Controller层开发 P0 3
5 应用编码生成器 P0 3
6 密钥生成与加密 P0 3
7 API签名验证拦截器 P0 3
8 缓存处理 P1 7
9 单元测试 P1 4

8.2.2 前端任务

序号 任务 优先级 依赖
1 API接口封装 P0 -
2 列表页面开发 P0 1
3 新增/编辑弹窗开发 P0 1
4 密钥展示弹窗开发 P0 1
5 Mock数据开发 P1 1
6 接口联调 P0 后端4
7 样式优化 P2 6

8.3 里程碑

里程碑 完成标准
M1 设计完成 技术方案通过评审
M2 后端完成 后端接口开发完成Postman可调试
M3 前端完成 前端页面开发完成Mock数据可运行
M4 联调完成 前后端联调通过,功能可正常使用
M5 验收完成 用户验收通过,可部署上线

9. 测试方案

9.1 测试范围

测试类型 测试内容
功能测试 应用CRUD、接口授权、密钥重置
接口测试 API签名验证、权限校验
性能测试 列表查询性能、签名验证性能
安全测试 密钥加密、防重放攻击

9.2 测试用例

9.2.1 功能测试用例

用例编号 用例名称 前置条件 测试步骤 预期结果
TC-APP-001 新增应用 已登录超管账号 1.点击新增 2.填写表单 3.选择接口 4.提交 应用创建成功,显示密钥
TC-APP-002 应用编码自动生成 已有应用YY000001 新增应用 新应用编码为YY000002
TC-APP-003 重置密钥 已有应用 点击重置密钥 弹窗显示新密钥,可复制
TC-APP-004 删除应用 已有应用 点击删除,确认 应用删除成功
TC-APP-005 禁用应用 已有应用 编辑状态为停用 应用无法调用API
TC-APP-006 接口授权 已有应用 勾选部分接口 仅授权接口可访问

9.2.2 接口测试用例

用例编号 用例名称 测试步骤 预期结果
TC-API-001 签名正确 使用正确密钥生成签名 请求成功
TC-API-002 签名错误 使用错误密钥生成签名 返回"签名验证失败"
TC-API-003 时间戳过期 使用10分钟前的时间戳 返回"请求已过期"
TC-API-004 应用禁用 使用禁用应用的密钥 返回"应用已禁用"
TC-API-005 无接口权限 访问未授权接口 返回"无权访问该接口"

9.3 验收标准

验收项 验收标准
功能完整性 所有P0功能用例通过
接口安全性 签名验证、权限校验正常
性能指标 列表查询 ≤500ms签名验证 ≤50ms
代码质量 无严重BUG代码规范检查通过

10. 风险评估

10.1 风险清单

风险编号 风险描述 影响程度 发生概率 应对措施
R01 密钥泄露 加密存储,传输加密,操作审计
R02 签名算法被破解 预留算法升级能力
R03 API被恶意调用 频率限制IP白名单预留
R04 权限变更不实时 使用缓存时设置合理过期时间

10.2 应对方案

R01 密钥泄露

  • 预防:密钥加密存储,只在新增和重置时显示一次
  • 发现:监控异常调用行为
  • 处置:支持立即重置密钥使旧密钥失效

R03 API被恶意调用

  • 当前:签名验证 + 时间戳防重放
  • 预留:接口频率限制(可后续添加)
  • 预留IP白名单机制可后续添加

附录

附录A墨刀原型对照

原型页面 对应功能 实现状态
应用管理-列表 应用列表查询 待开发
应用管理-编辑 新增/编辑应用、接口授权 待开发

附录B相关文档

文档名称 路径
需求规格说明书 docs/01-需求文档/需求规格说明书_v1.0.md
系统设计文档 docs/02-系统设计/系统设计文档_v1.0.md
数据库设计文档 docs/03-数据库设计/数据库设计文档_v1.0.md
接口设计文档 docs/04-接口文档/接口设计文档_v1.0.md

审核签字

角色 姓名 日期 签字
技术负责人
前端负责人
后端负责人
测试负责人

文档结束