## 架构要点 ### 请求流程 ``` External System → POST /api/com/{vendor}/{action} Header: X-Caller-Id: {callerId} X-Signature: {HMAC-SHA256(callerSecret, body+timestamp)} X-Timestamp: {unix ms} Body: { ...params aligned with base Client method args } ↓ CallerAuthInterceptor ├── 校验 X-Timestamp 5 分钟内 ├── CallerRegistryService.get(callerId) → callerSecret ├── 计算 HMAC 对比 └── 通过 → 继续;失败 → 401 ↓ GatewayController ├── 查 ActionWhitelist:{vendor}.{action} 是否开放 ├── 用反射或注册的 handler 调对应基座 Client 方法 └── 包 McR 返回 ``` ### 调用方注册(宜搭权限表单) 字段约定: | 宜搭字段 | 含义 | |---------|------| | `textField_callerId` | 调用方唯一 ID(签发时生成,如 `caller-YDCBC-001`) | | `textField_callerSecret` | HMAC 密钥(生成时返回给调用方,服务端也存,需加密字段) | | `textField_callerName` | 可读名称(便于审计) | | `textareaField_allowedActions` | JSON 数组:`["dingtalk.user.get", "aliwork.form.save"]`,精确白名单 | | `numberField_rateLimit` | 每秒限流上限 | | `radioField_enabled` | `on` / `off` | | `dateField_expireAt` | 密钥过期时间(可选) | ### Vendor Action 路由 为避免反射开销和控制边界,每个开放的 action 在代码里显式注册: ```java @Component public class DingtalkActionRegistry { @PostConstruct public void register(ActionRegistry reg) { reg.register("dingtalk.user.get", (ctx, body) -> { DDConf conf = resolveConf(ctx); // 可选:按 caller 配置不同 dingtalk 应用 return ddClient.getUserDetail(conf, body.getString("userid")); }); } } ``` `application.yml` 只维护"哪些 action 默认开放"的白名单;细粒度调用方权限通过宜搭权限表单的 `allowedActions` 限制。 ### 限流 - 本地 Guava `RateLimiter` 按 callerId 维度 - 单实例场景足够;若未来多实例部署再评估 Redis / 分布式限流 - 超限返回 `429 { code: "RATE_LIMITED" }` ### 审计 继承 `mjava-baseline §3.5` 审计规范,追加字段: | 字段 | 说明 | |------|------| | `callerId` | 调用方 ID | | `vendorAction` | `{vendor}.{action}` | | `signatureValid` | 签名校验结果 | 日志输出 `./log/{日期}/com-{callerId}.log`(按调用方分片)。 ## 安全要点 - `callerSecret` 存宜搭"加密字段"类型;内存访问后**不得**回传前端或记录到日志 - HMAC 防重放:`X-Timestamp` 5 分钟外拒绝 + 可选 Nonce(Phase 1 不做,5 分钟窗口足够内部场景) - 每次调用尝试失败都打 `WARN`,连续 5 次同 callerId 失败触发 `ERROR` 告警(`ExceptionNotice` 已有通道) ## Non-Goals(设计边界) - 不做 REST 规范化(不强制 HATEOAS / JSON:API) - 不做 WebSocket / 长连接 - 不做异步任务回调(请求同步完成,调用方需要异步能力自行轮询或用 mjava-pro) - 不做请求转发到非 mjava vendor(本质是 mjava Client 方法的 HTTP 门面)