pangu-user-platform/docs/05-模块技术方案/开放API-学生列表授权-技术设计方案.md

153 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 开放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<StudentVo>
```
### 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<String> apiCodes;`,用于接收前端与返回详情。
- **PgAppApiMapper**:新增方法,如 `List<String> selectApiPathsByAppCode(String appCode)`(联表 pg_api_dict 取 api_path
- **PgAppApiMapper.xml**:对应 SQLa.app_id = app_id 且 a.api_id = d.api_idd.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_LISTapi_name=学生列表api_path=/open/api/student/listapi_method=GETstatus=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 即可,鉴权与拦截器复用。