# 盘古用户平台 - 应用管理模块技术方案 --- | 文档信息 | 内容 | |---------|------| | **文档版本** | V1.0 | | **项目名称** | 盘古用户平台(Pangu User Platform) | | **模块名称** | 应用管理模块 | | **编写团队 | pangu | | **创建日期** | 2026-01-31 | | **审核状态** | 待评审 | --- ## 修订记录 | 版本 | 日期 | 修订人 | 修订内容 | |------|------|--------|----------| | V1.0 | 2026-01-31 | pangu | 初稿 | --- ## 目录 1. [模块概述](#1-模块概述) 2. [需求分析](#2-需求分析) 3. [系统设计](#3-系统设计) 4. [前端技术方案](#4-前端技术方案) 5. [后端技术方案](#5-后端技术方案) 6. [数据库设计](#6-数据库设计) 7. [接口设计](#7-接口设计) 8. [开发计划](#8-开发计划) 9. [测试方案](#9-测试方案) 10. [风险评估](#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 目录结构 ``` frontend/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 ... [>] │ └─────────────────────────────────────────────────────────────────┘ ``` **核心代码结构** ```vue ``` #### 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接口封装 ```javascript /** * 应用管理API接口 * @author pangu */ 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` | | 方法命名 | 小驼峰,如 `handleQuery`、`handleEdit` | | 事件处理 | 以 `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) ```java /** * 应用实体 * @author pangu */ @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) ```java /** * 应用管理服务接口 * @author pangu */ public interface IApplicationService { /** * 查询应用列表 */ List selectApplicationList(ApplicationDTO dto); /** * 查询应用详情 */ ApplicationVO selectApplicationById(Long appId); /** * 新增应用 * @return 返回应用编码和密钥 */ Map 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) ```java /** * 应用管理控制器 * @author pangu */ @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 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 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 应用编码生成 ```java /** * 生成应用编码 * 格式: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 密钥生成 ```java /** * 生成32位随机密钥 */ public String generateAppSecret() { return RandomUtil.randomString(32); } ``` #### 5.4.3 签名验证 ```java /** * 验证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 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分钟 | 应用授权的接口列表 | ```java /** * 清除应用缓存 * 在修改、删除、重置密钥时调用 */ public void clearAppCache(String appCode) { redisCache.deleteObject("app:info:" + appCode); redisCache.deleteObject("app:apis:" + appCode); } ``` --- ## 6. 数据库设计 ### 6.1 表结构 #### 6.1.1 应用表 (pg_application) ```sql 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) ```sql 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) ```sql 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 初始化数据 ```sql -- 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) | **请求示例** ```json { "appName": "AI智慧平台", "appDesc": "AI教育智慧平台", "contactPerson": "张经理", "contactPhone": "13812345678", "status": "0", "apiCodes": ["STUDENT_LIST", "SCHOOL_LIST", "GRADE_LIST"] } ``` **响应示例** ```json { "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) | **响应示例** ```json { "code": 200, "msg": "重置成功", "data": { "appSecret": "n1e2w3s4e5c6r7e8t9k0e1y2v3a4l5u6" } } ``` #### 7.1.7 获取API接口列表 | 项目 | 内容 | |------|------| | **接口地址** | `GET /api/application/apiList` | | **请求参数** | 无 | | **响应格式** | AjaxResult | **响应示例** ```json { "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签名示例** ```java public String generateSign(Map params, String appSecret) { // 1. 参数排序 Map 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 | --- ## 审核签字 | 角色 | 姓名 | 日期 | 签字 | |-----|------|------|------| | 技术负责人 | | | | | 前端负责人 | | | | | 后端负责人 | | | | | 测试负责人 | | | | --- *文档结束*