# 汇吉采 → 一站式代理平台:标书订单推送接口鉴权规范 > 用途:本文档是**本平台(汇吉采标书购买平台,下称「官方网」)调用一站式代理平台接口**时的鉴权规范,用于对接一站式平台开发人员,请对方按此规则在服务端做校验。 > 目标接口:`POST /api/biz/createPurchaseDetails`(本平台推送购买记录与订单信息到一站式平台落盘) --- ## 1. 共享凭证(双方提前约定,不通过网络传输) | 参数 | 值 | 说明 | |---|---|---| | `appKey` | `HJC_Official_Website` | 调用方标识,明文放在请求头 | | `password` | `vQ8$kR3#mW6@xP2!nF` | **签名密钥(Secret)**,仅双方服务端持有,**不放在请求头、不出现于任何请求/日志/报文** | > ⚠️ 出于安全考虑,本规范**不把 `password` 明文放请求头**。原始需求中「把 password 明文字段加到请求头」的做法会泄露密钥,改为「用 password 参与签名、请求头只带签名结果」的等价且更安全的方案(见第 3 节)。如需严格沿用原始「明文 password 头」方案,见附录 A。 --- ## 2. 请求头(请求方——官方网——每次调用携带 3 个) | Header | 示例值 | 说明 | |---|---|---| | `appKey` | `HJC_Official_Website` | 明文 appKey(固定值) | | `timestamp` | `202604080103` | 签名时间,格式 `yyyyMMddHHmm`(24 小时制,北京时区,精确到分钟) | | `sign` | `9f7c…(32 位小写十六进制)` | 签名值,算法见第 3 节 | 另需:`Content-Type: application/json`。 --- ## 3. 签名算法 ``` sign = MD5( appKey + password + timestamp ) ``` - `+` 表示**字符串直接拼接**,中间无分隔符。 - `timestamp` 使用与请求头 `timestamp` **完全相同**的值。 - `MD5` 输出**小写** 32 位十六进制字符串。 步骤: 1. 取当前北京时间的分钟表示 `timestamp = yyyyMMddHHmm`(例:`2026-04-08 01:03` → `202604080103`)。 2. 拼串:`HJC_Official_Website` + `vQ8$kR3#mW6@xP2!nF` + `202604080103`。 3. 对该字符串做 MD5,转小写,得到 `sign`。 4. 将 `appKey`、`timestamp`、`sign` 放入请求头发出。 --- ## 4. 校验规则(一站式平台服务端) 收请求后按以下顺序校验,任一步不通过即拒绝(建议返回 `401` / `400`,并附错误码与说明,便于排查): 1. **校验 appKey**:`appKey` 是否等于已登记的应用标识 `HJC_Official_Website`。不等 → 拒绝。 2. **校验 timestamp 时效(防重放)**:`timestamp` 与**一站式服务器当前时间**之差是否在 **±10 分钟**以内(统一按北京时区、分钟精度)。超出窗口 → 拒绝,提示「时间戳失效」。 - 该窗口同时限制了重放窗口;如需更严可协商收紧到 ±3 分钟。 3. **校验签名**:用共享的 `password` 重算 `MD5(appKey + password + timestamp)`,与请求头 `sign` **不区分大小写**比较(统一小写后比较)。不一致 → 拒绝,提示「签名校验失败」。 4. 校验通过后,按请求体 `createPurchaseDetails` 的字段约定解析并落盘(业务字段见单独一节的「createPurchaseDetails 请求体字段表」)。 --- ## 5. 幂等与重试约定(可选但强烈建议) `createPurchaseDetails` 是「落盘」类写操作,本平台侧会做失败重试,因此建议一站式平台按业务主键幂等处理,避免重复落盘: - 请求体需带唯一业务单号(如 `purchaseId` / `orderNo`),一站式平台以此作为去重键;**同一单号重复提交时应返回成功、不重复插入**(或返回「已存在」)。 - 本平台对失败的推送会按 `attempt` 递增重试(建议:1/2/4/8 分钟间隔),重试时 `timestamp/sign` 需要**重新计算**(每次请求都要以新时间重签)。 --- ## 6. 双端示例 **官方网(请求方)**——以 Python 为例: ```python import hashlib, time, requests app_key = "HJC_Official_Website" password = "vQ8$kR3#mW6@xP2!nF" ts = time.strftime("%Y%m%d%H%M") # 202604080103 sign = hashlib.md5((app_key + password + ts).encode("utf-8")).hexdigest() resp = requests.post( "https://<一站式域名>/api/biz/createPurchaseDetails", json={ ... 业务字段 ... }, headers={ "appKey": app_key, "timestamp": ts, "sign": sign, "Content-Type": "application/json", }, timeout=15, ) ``` **一站式(校验方)**——以 Java 为例: ```java String appKey = req.getHeader("appKey"); String ts = req.getHeader("timestamp"); String sign = req.getHeader("sign"); if (!"HJC_Official_Website".equals(appKey)) return 401; // 1 if (Math.abs(System.currentTimeMillis() / 60000 - parseMinute(ts)) > 10) return 401; // 2 String expect = md5("HJC_Official_Website" + SECRET + ts); // 3 if (!expect.equalsIgnoreCase(sign)) return 401; // 4. 解析 body,按 createPurchaseDetails 字段落盘(按 orderNo 幂等) ``` --- ## 附录 A:若一站式平台坚持「明文 password 头」的原始方案 原始需求表述为「请求头添加 appKey、password,appKey+年月日时分、password+年月日时分,MD5 加密」。若对方已按此固定算法实现,则采用: - 请求头:`appKey=HJC_Official_Website`、`password=vQ8$kR3#mW6@xP2!nF`、`sign=MD5(password + yyyyMMddHHmm)`(小写)。 - 校验:`password` 需与约定值一致,且 `MD5(password + timestamp) == sign`,同时 `timestamp` 在 ±10 分钟内。 > 该方案会把 `password` 以明文形式暴露在报文中,安全性差;**仅作兼容退路,不作为默认推荐**。若对方无法确认固定算法,请首选第 1–6 节的方案。 --- ## 附:需要一站式平台确认/提供的信息 1. 上述 `sign` 拼接顺序是否与合作方既有算法一致(`appKey+password+timestamp`)。 2. 时间戳格式 `yyyyMMddHHmm` 与北京时区是否认可。 3. 校验窗口 ±10 分钟是否可接受。 4. `createPurchaseDetails` 请求体字段表(本平台另一份文档,见需求/接口清单)的具体入参名与必填项,需对方给出或双方对齐,以免字段名不一致导致落盘失败。