# 开放API-学生列表授权 技术设计方案 > 作者:pangu > 创建时间:2026-02-04 > 评审状态:待评审 --- ## 一、总体架构 ### 1.1 请求链路 ``` 外部请求 GET /open/api/student/list?pageNum=1&pageSize=10 → 不经过 Sa-Token 登录校验(security.excludes 排除 /open/api/**) → ApiAuthInterceptor 拦截 /open/api/** → 校验 X-App-Id、X-Timestamp、X-Sign → 查应用信息、校验接口授权 → OpenApiStudentController.list() → IPgStudentService.selectPageList() → 返回 TableDataInfo ``` ### 1.2 模块与职责 | 模块/组件 | 职责 | |-----------|------| | Security 配置 | 将 `/open/api/**` 加入排除路径,不校验登录 | | ApiAuthInterceptor | 仅对 `/open/api/**` 生效:校验头、签名、接口授权 | | OpenApiStudentController | 提供 GET `/open/api/student/list`,委托现有 StudentService | | IPgApplicationService | 新增 selectByAppCode、checkApiPermission;新增/编辑时同步 pg_app_api | | PgAppApiMapper | 新增按 appCode 查授权 api_path 列表方法(联表 pg_api_dict) | | pg_api_dict | 增加「学生列表」开放接口记录,api_path=/open/api/student/list | --- ## 二、安全与鉴权 ### 2.1 请求头约定 | 请求头 | 必填 | 说明 | |--------|------|------| | X-App-Id | 是 | 应用编码(appCode) | | X-Timestamp | 是 | 当前时间毫秒时间戳,防重放 | | X-Sign | 是 | 签名,见 2.2 | ### 2.2 签名算法 1. 将请求参数(Query 与 Body,仅一层 key-value)按参数名 ASCII 升序排序。 2. 拼接为:`key1=value1&key2=value2&...&appSecret=应用密钥`(appSecret 为服务端存储的密钥)。 3. 对上述字符串做 **MD5**,结果转为 **大写**,即 X-Sign。 示例(GET,无 body): - 请求:GET /open/api/student/list?pageNum=1&pageSize=10 - 假设 appSecret=abc123 - 参数字符串:`pageNum=1&pageSize=10&appSecret=abc123` - sign = MD5(参数字符串).toUpperCase() ### 2.3 时间戳防重放 - 服务端收到 X-Timestamp 后,与当前服务器时间比较,若 |now - timestamp| > 5 分钟,返回 400「请求已过期」。 ### 2.4 接口授权校验 - 请求 URI 取 path(如 `/open/api/student/list`),与当前应用在 pg_app_api + pg_api_dict 中关联的 api_path 集合比对;不在集合内则返回 403「无权访问该接口」。 --- ## 三、接口设计 ### 3.1 开放接口:学生列表 | 项目 | 说明 | |------|------| | 方法 | GET | | 路径 | /open/api/student/list | | 鉴权 | 应用签名 + 接口授权 | | 参数 | 与现有 /business/student/list 一致:studentName、studentNo、schoolId、schoolGradeId、schoolClassId、status 等;分页 pageNum、pageSize | | 响应 | 与现有一致:`{ code, msg, rows, total }`(TableDataInfo) | ### 3.2 错误响应 | HTTP 状态 | 场景 | 示例 msg | |-----------|------|----------| | 400 | 缺少认证参数 / 时间戳格式错误 / 请求已过期 | 缺少认证参数 | | 401 | 应用不存在 / 应用已停用 / 签名验证失败 | 签名验证失败 | | 403 | 未授权该接口 | 无权访问该接口 | --- ## 四、数据与缓存 ### 4.1 表使用 - **pg_application**:已有;需按 app_code 查询(selectByAppCode)。 - **pg_api_dict**:已有;需新增一条 api_path=`/open/api/student/list` 的记录,供授权勾选与校验。 - **pg_app_api**:已有;新增/编辑应用时按 apiCodes 写入/更新;鉴权时按 app_id 联表 pg_api_dict 得到 api_path 列表。 ### 4.2 授权生效 - 方案 A:每次请求查库(或查缓存)。 - 方案 B:应用授权变更时更新缓存,校验时先查缓存。 本期可采用**不缓存**或**短 TTL(如 5 分钟)缓存**「应用授权 path 集合」,技术实现时在 Service 中按 appCode 查授权 path 列表即可;若后续性能有要求再加 Redis。 --- ## 五、实现清单 ### 5.1 配置 - **application.yml**:security.excludes 增加 `/open/api/**`。 ### 5.2 应用模块(application) - **IPgApplicationService**:新增 `PgApplication selectByAppCode(String appCode)`、`boolean checkApiPermission(String appCode, String apiPath)`。 - **PgApplicationServiceImpl**:实现上述方法;insert/update 时增加对 apiCodes 的处理,同步 pg_app_api(先删后插)。 - **PgApplication**:增加 `@TableField(exist = false) private List apiCodes;`,用于接收前端与返回详情。 - **PgAppApiMapper**:新增方法,如 `List selectApiPathsByAppCode(String appCode)`(联表 pg_api_dict 取 api_path)。 - **PgAppApiMapper.xml**:对应 SQL(a.app_id = app_id 且 a.api_id = d.api_id,d.api_path)。 ### 5.3 开放 API 模块(新建或放在 business 下) - **OpenApiConfig**:WebMvcConfigurer,注册 ApiAuthInterceptor,仅 addPathPatterns("/open/api/**")。 - **ApiAuthInterceptor**:preHandle 中取 X-App-Id、X-Timestamp、X-Sign;校验时间戳 → selectByAppCode → 校验签名 → checkApiPermission(uri) → 通过则 return true。 - **OpenApiStudentController**:GET `/open/api/student/list`,参数与 PgStudentController.list 一致,委托 IPgStudentService.selectPageList。 ### 5.4 接口字典数据 - 在 pg_api_dict 中 INSERT 一条:api_code=OPEN_STUDENT_LIST,api_name=学生列表,api_path=/open/api/student/list,api_method=GET,status=0。可使用 SQL 脚本或启动时初始化。 ### 5.5 前端 - 已有接口授权勾选(apiCodes)与 apiList 接口;只需保证后端保存/回显 apiCodes 与 pg_app_api 一致即可,无需改前端逻辑(若当前未回显 apiCodes,需后端在查询应用详情时填充 apiCodes)。 --- ## 六、调用测试说明 - 提供「开放API-学生列表授权-调用测试说明.md」或同目录下测试脚本: - 签名算法说明与示例(含 GET 示例)。 - 示例:在管理端创建应用并勾选「学生列表」,记录 appCode、appSecret,用 curl 或 Postman 调用 GET /open/api/student/list,携带正确 X-App-Id、X-Timestamp、X-Sign。 - 预期:授权应用返回 200 与列表数据;未授权或错误签名返回 401/403。 --- ## 七、评审要点 1. 开放路径仅限 `/open/api/**`,与现有 /business、/h5 隔离,且不校验用户登录。 2. 签名算法与请求头约定是否满足安全与对接方实现成本平衡。 3. 学生列表参数与响应与现有一致,避免业务逻辑重复。 4. 应用管理侧保存/回显接口授权与 pg_app_api、pg_api_dict 数据一致性。 5. 后续扩展其他开放接口时,仅需在 pg_api_dict 加记录、新增对应 OpenApiXxxController 即可,鉴权与拦截器复用。