看店通 OpenAPI 采用「应用凭证换取访问令牌 + 敏感接口附加签名」的鉴权机制,确保只有获得授权的服务端可以访问商户数据。本文是全站开发者文档中关于认证的唯一权威说明:OpenAPI 总览、API 接口文档、SDK 接入指南中如与本文表述不一致,一律以本文为准。
环境域名、AppId 与 AppSecret 由项目交付或商户后台「开发者 → 应用管理」提供。AppSecret 属于服务端机密,请勿写入小程序前端代码、H5 页面、App 客户端或公开代码仓库;一旦出现在客户端包体中,即视为已泄露,必须立即轮换。
一、鉴权模型概览
完整流程分三步:第一步用 AppId 与 AppSecret 调用令牌接口换取 access_token;第二步在业务请求头中携带
Authorization: Bearer {access_token};第三步,若调用的是退款、提现、批量改价等敏感写接口,还需按第三节的规则附加 HMAC-SHA256 签名,以防篡改与重放。只读接口无需签名,仅需令牌。
- AppId:应用标识,非机密,可出现在日志与工单中,便于定位调用方。
- AppSecret:仅服务端保存,用于换取令牌和计算签名,泄露需立即轮换。
- access_token:有效期 7200 秒(2 小时),应在进程内或 Redis 中缓存并复用,剩余不足 300 秒时提前刷新;收到 401 时刷新一次并重试,避免无限重试风暴。
令牌为「商户 + 应用」维度,不是「用户」维度。同一个 AppId 在多台机器上重复调用令牌接口会得到同一个仍在有效期内的令牌,因此不要为每个请求单独换取令牌,那会迅速触发限流。
二、获取访问令牌
令牌接口为 POST https://api.kandiantong.com/v1/oauth/token,请求体为 UTF-8 编码的 JSON。请求示例:
POST /v1/oauth/token HTTP/1.1
Host: api.kandiantong.com
Content-Type: application/json
{
"grant_type": "client_credentials",
"app_id": "kdt_app_10086",
"app_secret": "your_app_secret"
}
成功响应(HTTP 200):
{
"code": 0,
"message": "success",
"request_id": "req_7f3c9a12b4e5",
"data": {
"access_token": "your_access_token",
"token_type": "Bearer",
"expires_in": 7200
}
}
后续业务请求携带令牌即可:
GET /v1/orders?page=1&page_size=20 HTTP/1.1
Host: api.kandiantong.com
Authorization: Bearer your_access_token
注意
expires_in
是相对秒数而非绝对时间,缓存时请换算成本机到期时间戳再存储;直接存相对值会在进程重启后失效判断错误。
三、签名算法
敏感写接口在令牌之外要求签名。签名对象是「请求方法 + 路径 + 排序后的查询参数 + 请求体原文 + 时间戳 + 随机串」拼成的规范化字符串,算法固定为 HMAC-SHA256,输出小写十六进制:
canonical = method + "\n" + path + "\n" + sorted_query + "\n"
+ sha256_hex(raw_body) + "\n" + timestamp + "\n" + nonce
signature = hmac_sha256_hex(<APP_SECRET>, canonical)
规范化规则:过滤值为空的参数;剩余参数按 key 的字典序升序排列,拼成
key=value&key=value;值按 RFC 3986 做 URL 编码。三个必备请求头如下:
| 请求头 | 取值 | 说明 |
|---|---|---|
X-Kdt-Timestamp |
Unix 秒级时间戳 | 服务端校验 ±300 秒时间窗,超窗返回业务码 40003 |
X-Kdt-Nonce |
32 位随机串 | 服务端在时间窗内校验唯一性,重复即判定为重放 |
X-Kdt-Signature |
小写十六进制签名值 | 与服务端计算结果做定长比较 |
三个容易踩的坑:一是签名必须基于 raw body,如果框架中间件(如日志、字段裁剪、JSON 重序列化)改写过请求体,签名必然失败;二是服务器时钟必须接入 NTP,机器时间漂移超过 5 分钟会导致全量请求
40003;三是签名串中不要包含文件二进制流,上传类接口请改用分步鉴权,先调用上传接口换取临时 upload_token,再用该令牌提交文件。
四、权限范围(Scope)
授权按最小权限原则开通,只读与读写分离,模块之间互不牵连。申请时请按实际用途勾选,而不是图省事全选——一旦密钥泄露,未开通的 scope 就是最后一道防线。
| Scope | 覆盖能力 | 典型申请方 |
|---|---|---|
order:read |
订单查询、订单明细、物流轨迹查询 | ERP、客服工作台 |
order:write |
发货回写、关闭订单、修改备注 | WMS |
product:read |
商品与 SKU 查询、分类查询 | ERP、运营工具 |
product:write |
商品与 SKU 创建、改价、上下架 | PIM、ERP 主数据 |
inventory:write |
库存同步、预占与回滚 | WMS |
member:read |
会员信息、等级、积分查询(手机号默认脱敏) | CRM、SCRM |
refund:write |
发起退款、审批售后单 | 财务系统 |
权限变更需商户管理员在后台审批,系统会留存审批人、时间与变更前后的 scope 列表。集成 ERP 时通常只需
order:read、order:write、inventory:write
三项,不必开通营销类接口。调用了未授权的接口会返回 HTTP 403,而不是 401,据此可以快速区分「令牌无效」与「权限不足」。
五、调用约定
以下约定适用于全部 OpenAPI 接口,其他文档页沿用同一套规则,不再重复定义:
- Base URL:
https://api.kandiantong.com/v1,全程 HTTPS(TLS 1.2 及以上),不提供 HTTP 明文入口。 - 字段命名:统一 snake_case。订单号字段在所有接口与回调中一律为
order_no,不存在orderNo、order_sn等别名。 - 时间格式:业务时间字段统一用 ISO 8601 带时区偏移,例如
2026-09-29T20:30:00+08:00;只有签名用的X-Kdt-Timestamp使用 Unix 秒级时间戳。两者不要混用。 - 分页:
page从 1 开始,page_size默认 20、最大 100;超过 10 万行的数据请改用异步导出。 - 限流:每个 AppId 读接口 600 次/分钟、写接口 120 次/分钟,超限返回 HTTP 429 并携带
Retry-After响应头。 - 幂等:所有写接口支持
Idempotency-Key请求头,同一 key 在 24 小时内重复提交返回首次结果。
六、密钥轮换
- 在后台「开发者 → 应用管理 → 密钥」生成新 AppSecret,此时新旧两把密钥双活。
- 保持双活 24 至 72 小时,逐个集成方切换配置,并在网关监控中确认旧密钥调用量归零、无新增 401。
- 在后台手动作废旧 AppSecret,不要依赖「到期自动失效」。
- 将轮换事件写入变更单,记录操作人、时间、涉及的集成方清单与回滚方案。
触发紧急轮换的情形包括:密钥被提交到代码仓库(即使已 force push 删除,也应视为泄露)、离职人员曾接触过密钥、日志系统中出现明文密钥、收到异常调用告警。紧急轮换时跳过双活期直接作废,宁可短时中断也不要留窗口。
七、错误码与排查
HTTP 状态码表示传输层与权限层结果,响应体中的 code 表示业务结果,code 为 0 代表成功。二者不一致时以 code 为准。每个响应都带 request_id,提工单时请一并提供。
| HTTP / 业务码 | 含义 | 建议处理 |
|---|---|---|
| 400 | 参数缺失或格式错误 | 对照接口文档核对必填项与枚举值,不要重试 |
| 401 | 令牌缺失、无效或已过期 | 刷新令牌后重试一次;仍失败则检查 AppId 与环境是否匹配 |
| 403 | 权限不足,scope 未开通 | 在后台申请对应 scope,或改用有权限的 AppId |
| 404 / 40401 | 资源不存在 | HTTP 404 表示传输层未找到资源;业务码 40401 表示订单号或 SKU 不属于当前商户。跨商户访问同样按不存在处理,不要据此推断资源是否真实存在 |
| 429 | 触发限流 | 读取 Retry-After 后指数退避;批量任务改为异步队列 |
| 500 | 服务端异常 | 可重试,建议最多 3 次并逐次加大间隔;持续失败请带 request_id 报障 |
| 40001 | 签名校验失败 | 检查是否对 raw body 签名、参数是否漏掉空值过滤、AppSecret 首尾是否有多余空格 |
| 40003 | 时间戳超出 ±300 秒时间窗 | 校准服务器 NTP;跨时区部署时确认时间戳取的是 UTC 秒数 |
| 40005 | nonce 重复,判定为重放 | 每次请求重新生成随机串,不要在重试时复用 |
八、上线前自检清单
- 生产与测试使用两套独立的 AppId 和 AppSecret,配置文件物理隔离,禁止共用。
-
密钥通过密钥管理服务(KMS、Vault 或云厂商配置中心)下发,不以明文写入
.env并提交到版本库。 - CI/CD 流水线使用专用的沙箱凭证,构建日志中对密钥做掩码处理。
- 应用日志只记录 AppId 与 request_id,禁止打印 AppSecret、access_token 与完整签名串。
- 令牌已做进程外缓存(如 Redis)并加分布式锁,避免多实例同时刷新。
- 已实现 401 刷新重试、429 退避、5xx 有限重试三类兜底逻辑,且重试次数有上限。
- 已完成一次时钟漂移演练:手动把测试机时间调偏 10 分钟,确认能拿到 40003 而不是静默失败。
更多服务端加固要求见安全规范;接口全景与版本策略见OpenAPI 总览;回调侧的验签规则见事件回调 Webhook,两者使用的是不同的密钥,请勿混用。