开发规范
开发规范
本文将 调用约定 与 签名 合并为单页,便于打印或旧链接跳转。日常阅读建议使用 调用约定 与 签名 分主题页;错误码见 错误码。
接口域名
| 请求类型 | 域名 |
|---|---|
| HTTP POST | https://openapi.lechange.cn:443/openapi/[method] |
[method] 为接口方法名(如 accessToken、bindDevice)。URL 路径不含版本号;协议版本写在请求体 system.ver(当前固定 1.0)。
请求体结构
| 字段 | 类型 | 说明 |
|---|---|---|
system.ver | String | 协议版本,当前为 1.0 |
system.sign | String | 签名,计算见 签名 |
system.appId | String | 应用 ID,在 控制台 · 我的应用 · 应用信息 获取 |
system.time | Long | 客户端 UTC 时间戳(秒),与平台时间误差不超过 5 分钟,否则 SN1002 |
system.nonce | String | 随机字符串;可用标准 UUID(含连字符,见下例)或 32 位十六进制串。5 分钟内不可重复,否则 SN1005 |
params | Map | 各接口业务参数 |
params.token | String | 多数业务接口必填(管理员或子账号 accessToken)。accessToken 等少数方法自身不需要;缺失或无效 → OP1007(见 错误码) |
id | String | 请求唯一 ID,建议 UUID |
获取管理员 token 的请求示例(sign 需按签名规则自行计算):
{
"system": {
"ver": "1.0",
"appId": "lcdxxxxxxxxx",
"sign": "xjhCQBoJ9hRDsCjyDcHjtDNzRZ3ZJezcawsfWeiaoxU=",
"time": 1706511734,
"nonce": "f5a1ae2d-c09c-4d39-a744-83a5c2c653c2"
},
"id": "98a7a257-c4e4-4db3-a2d3-d97a3836b87c",
"params": {}
}
响应体结构
| 字段 | 类型 | 说明 |
|---|---|---|
result.code | String | 返回码,0 为成功;分组见 错误码 |
result.msg | String | 返回码描述 |
result.data | Map | 业务数据 |
id | String | 与请求中的 id 一致 |
成功响应示例:
{
"result": {
"msg": "操作成功。",
"code": "0",
"data": {
"expireTime": 259176,
"accessToken": "<yourAccessToken>"
}
},
"id": "98a7a257-c4e4-4db3-a2d3-d97a3836b87c"
}
HTTP 状态码为 200 时仍可能出现业务失败,以 body 内 result.code 为准。
计算步骤
- 签名原始串(UTF-8):将
time、nonce、appSecret按键值对拼接,顺序为 time → nonce → appSecret,英文逗号分隔:
签名原始串 = time:{time},nonce:{nonce},appSecret:{appSecret}
appSecret 在 控制台 · 我的应用 · 应用信息 获取,仅用于服务端。
- 派生密钥
password:对appSecret做 SHA-256,结果转为小写十六进制:
password = LowerCase(Hex(SHA-256(appSecret)))
- 计算
sign:以password为密钥,对签名原始串做 HMAC-SHA256,再 Base64 编码:
sign = Base64(HMAC-SHA256(签名原始串, password))
时间戳与 nonce 约束见 调用约定(错误码 SN1002、SN1005)。
代码示例(Java)
import org.apache.commons.codec.digest.DigestUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.time.Instant;
import java.util.Base64;
import java.util.UUID;
Long time = Instant.now().getEpochSecond();
String nonce = UUID.randomUUID().toString();
String appSecret = "test123456789test123456789";
String SIGN_TEMPLATE = MessageFormat.format(
"time:{0},nonce:{1},appSecret:{2}", time.toString(), nonce, appSecret);
String password = DigestUtils.sha256Hex(appSecret).toLowerCase();
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(password.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] digest = mac.doFinal(SIGN_TEMPLATE.getBytes(StandardCharsets.UTF_8));
String sign = Base64.getEncoder().encodeToString(digest);
标准案例
用下列固定入参在本地试算;结果与案例一致即表示实现正确。
| 入参 | 值 |
|---|---|
| time | 1706511734 |
| nonce | f5a1ae2d-c09c-4d39-a744-83a5c2c653c2 |
| appSecret | test123456789test123456789 |
步骤 1 — 签名原始串:
time:1706511734,nonce:f5a1ae2d-c09c-4d39-a744-83a5c2c653c2,appSecret:test123456789test123456789
步骤 2 — password:
1f2da89b2fab404859f02bcc80e8521bc7a63af3e5b1da5318f7cf7c56836b09
步骤 3 — sign:
xjhCQBoJ9hRDsCjyDcHjtDNzRZ3ZJezcawsfWeiaoxU=
对应 system 示例:
{
"system": {
"ver": "1.0",
"appId": "lcdxxxxxxxxx",
"sign": "xjhCQBoJ9hRDsCjyDcHjtDNzRZ3ZJezcawsfWeiaoxU=",
"time": 1706511734,
"nonce": "f5a1ae2d-c09c-4d39-a744-83a5c2c653c2"
},
"id": "98a7a257-c4e4-4db3-a2d3-d97a3836b87c",
"params": {}
}