主题
4.1 Token 鉴权
鉴权验证「请求合法、未被篡改」。JoyInside 用 HMAC-MD5 V2 签名 + 双 Token 机制:签名防篡改,Token 是调用 API 的临时凭证。
Token 生命周期(双 Token 机制)
签名验证通过后,服务端签发 Token,后续请求(建 WS、设备注册等)携带 Token 即可,无需每次重算签名。双 Token 机制:
签名算法(HMAC-MD5 V2)
服务端用相同规则生成签名,若与客户端一致则视为合法。accessKeySecret 必须保密,不泄露给客户端。
签名参数:
| 参数 | 说明 |
|---|---|
accessVersion | 认证算法版本,固定 V2 |
accessTimestamp | 13 位毫秒时间戳,与服务端时间误差 ≤ 5 分钟 |
accessNonce | 随机字符串(建议 32 位 UUID),防重放,每次请求必须不同 |
accessKeyId | 开发者中心 > API 密钥 中的 AccessKey |
签名计算步骤:
python
# 1. 准备参数(不含 accessSign)
params = {
"accessVersion": "V2",
"accessTimestamp": str(int(round(time.time() * 1000))),
"accessNonce": str(uuid.uuid4()),
"accessKeyId": "你的 AccessKey"
}
# 2. key 转小写,按参数名字母序排序
lower_key_params = {k.lower(): params[k] for k in params}
sorted_params = sorted(lower_key_params.items(), key=lambda item: item[0])
# 3. 拼接 key=value,用 & 连接
joint_params = '&'.join([f'{k}={str(v)}' for k, v in sorted_params])
# 4. HMAC-MD5 加密,SecretKey 作为 key
h = hmac.new("你的 SecretKey".encode('utf-8'),
joint_params.encode('utf-8'),
digestmod=hashlib.md5)
access_sign = binascii.hexlify(h.digest()).decode('utf-8')注意事项:
⚠ 密钥安全:
accessKeySecret必须保密,不要写在客户端代码或前端⚠ 时间戳有效期:确保与服务端时间误差在 5 分钟内(建议接入 NTP 校准)
⚠ 随机数防重放:
accessNonce每次请求必须不同,防止请求被重复使用✅ 编码一致:所有参数必须 UTF-8 编码
获取访问令牌
getToken 接口:
| 项 | 值 |
|---|---|
| URL | https://api.joyinside.com/auth/getToken |
| 方式 | POST |
| 作用 | 用签名获取 Token |
请求参数:
Body
| 字段 | 必选 | 说明 |
|---|---|---|
| accessKeyId | 是 | AccessKey |
| accessTimestamp | 是 | 13 位毫秒时间戳(≤5min) |
| accessNonce | 是 | 随机数(防重放) |
| accessVersion | 是 | 固定 V2 |
| accessSign | 是 | 签名(参见签名算法) |
| botId | 否 | 设备唯一标识,与 vendorId 二选一。已注册设备用 botId |
| vendorId | 否 | 厂商唯一标识,与 botId 二选一。注册设备用 vendorId |
⚠ botId 与 vendorId 同时存在时,优先用 botId 生成授权令牌。
⚠ 用 botId 获取令牌时,必须用已注册的 botId,且保证与其他 botId 不重复。
请求示例
完整 请求示例(点击展开)
shell
curl --location 'https://api.joyinside.com/auth/getToken' \
--header 'Content-Type: application/json' \
--data '{
"accessVersion": "V2",
"accessTimestamp": "1234567890",
"accessNonce": "a",
"accessKeyId": "1",
"accessSign": "2",
"botId": "1"
}'
注意:参数botId与vendorId同时存在时,优先使用botId生成授权令牌响应参数:
| 字段 | 说明 |
|---|---|
| accessToken | 访问令牌,有效期 8 小时 |
| expireIn | 访问令牌剩余有效时间(秒) |
| refreshToken | 刷新令牌,有效期 7 天 |
| refreshExpireIn | 刷新令牌剩余有效时间(秒) |
| code | 状态码 |
| msg | 状态信息 |
响应示例
完整 响应示例(点击展开)
json
{
"accessToken": "ehuc2065edbru==",
"expireIn": 7200,
"refreshToken": "cjekcnlsjfekncejh==",
"refreshExpireIn": 604800,
"code": 0,
"msg": ""
}刷新访问令牌
Token 过期前,用 refreshToken 换新的 accessToken,无需重新签名。refreshToken 也过期后,需重新走签名流程。
refreshToken 接口:
| 项 | 值 |
|---|---|
| URL | https://api.joyinside.com/auth/refreshToken |
| 方式 | POST |
| 作用 | 用 refreshToken 换新 accessToken |
请求参数:
Body
| 字段名称 | 类型 | 是否必选 | 说明 |
|---|---|---|---|
| accessKeyId | String | 是 | APP访问密钥ID |
| refreshToken | String | 是 | 刷新令牌 |
| botId | String | 否 | 设备唯一标识 (获取方式)。botId与vendorId二者必选其一 |
| vendorId | String | 否 | 厂商唯一标识 (获取方式)。botId与vendorId二者必选其一 |
vendorId使用场景
新设备配网后,设备自动注册JoyInside平台,获取设备唯一标识(botId)
botId使用场景
设备已注册,使用设备botId获取访问授权,调用语音、文本对话等API服务
请求示例
完整 请求示例(点击展开)
shell
curl --location 'https://api.joyinside.com/auth/refreshToken' \
--header 'Content-Type: application/json' \
--data '{
"accessKeyId": "xxxx",
"refreshToken": "adasdfjklji1752==",
"botId": "c22065edb"
}'
注意:参数botId与vendorId同时存在时,优先使用botId生成授权令牌响应参数:
Body
| 字段名称 | 类型 | 是否必选 | 说明 |
|---|---|---|---|
| accessToken | String | 必选 | 用户访问令牌 |
| expireIn | Integer | 必选 | 访问令牌过期时间(秒),有效期8小时,失效后重新生成或使用refreshToken生成新accessToken |
| code | Integer | 必选 | 状态码 |
| msg | String | 必选 | 状态对应信息 |
响应示例
完整 响应示例(点击展开)
json
{
"accessToken": "aaaaaaazI1NiJ9.bbbbbMHZqcCfG2_JOb.LFhU0QeI1EI9J-GQ6-CjoWvj4q3SdZs",
"expireIn": 7200,
"code": 0,
"msg": ""
}刷新参数必须与签名参数一致:刷新时传入的 vendorId/botId 必须与原 getToken 一致。
生产环境刷新策略(详见 11.1 Token 刷新策略):
- accessToken 剩余 30 分钟时主动用 refreshToken 刷新
- 设备启动时先校验本地缓存的 Token 是否有效
- refreshToken 临过期前(如剩余 1 天)重新走签名流程
Token 在后续请求中的使用
HTTP 接口(如设备注册):
Header: Authorization: Bearer ${accessToken}WebSocket 建连:
Header: Authorization: Bearer ${accessToken}鉴权失败场景(按现象排查)
注:本节列出鉴权失败的现象与原因,帮助排查。具体错误码值见 9.7 错误码速查。
getToken 阶段失败(HTTP 200 返回,看 code 字段)
| code | 现象 | 怎么修 |
|---|---|---|
| 1001 | 参数非法 | 必填参数缺失,或 vendorId+botId 都为空 → 补齐五个签名参数,至少传 vendorId 或 botId 之一 |
| 1002 | 版本号错误 | accessVersion 非 V2 → 改为 V2 |
| 1003 | 时间戳错误 | 不是 13 位毫秒 / 超 5 分钟误差 → 用 13 位毫秒时间戳,接入 NTP 校准 |
| 1004 | 企业或设备不存在 | vendorId/botId 服务端查不到 → 核对 ID 复制无误,确认企业/设备已创建 |
| 1005 | 签名不合法 | 客户端签名与服务端不一致 → 核 SecretKey、key 转小写、字母序排序、& 拼接、UTF-8 编码 |
| 1006 | 系统异常 | 服务端生成签名出错 → 重试,持续失败联系支持 |
WebSocket 建连鉴权失败
⚠ WS 建连鉴权失败时,服务端统一返回错误码400,错误信息明细如下。
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
botId not found or invalid | 缺少鉴权参数(vendorId/botId 都没传) | 检查 WS URL 的 botId 参数 |
Unauthorized | 企业配置不合格(如 AccessKey/SecretKey 配置缺失) | 核对平台企业信息与 API 密钥 |
Unauthorized | Token 错误或已过期 | 重新 getToken,确保在建连前刷新;确认 accessToken 没拼错 |
REPEAT_CLIENT_SESSION 互踢 | 同 botId 建了第二个 WS 连接 | 一个 botId 只保持一个 WS 连接,详见 设备注册与绑定 双连接互踢 |
Token 2 小时有效期:建议在 WS 建连前重新获取 Token,避免建连时已过期。详见 11.1 Token 刷新策略。
下一步
- 设备注册与绑定:4.2 设备注册与绑定
- 核心参数总表:4.3 重要参数介绍
- 排查鉴权问题:9.1 建连失败类