帮你快速理解、总结文档立即下载

设备密钥认证

最近更新时间:2026-09-11 16:05:33
我的收藏
本文将介绍设备如何使用 ProductID、DeviceName 和设备密钥生成 MQTT 连接参数,并完成设备身份认证和上线。

功能介绍

设备密钥认证使用平台为每台设备生成的独立设备密钥(DeviceSecret)验证设备身份。设备使用 DeviceSecret 对 MQTT Username 进行 HMAC 签名,并将签名结果组成 Password;平台校验通过后,设备即可上线。
注意:
本文中的 DeviceSecret 也称为 PSK。DeviceSecret 属于敏感凭证,请妥善保管。
如果尚未确定使用设备密钥认证还是设备证书认证,请参见 认证方式概览

认证流程

设备密钥认证流程参见下图:


认证参数

如需在控制台查看并复制设备身份参数及 MQTT 连接参数,请参见 获取设备三元组

设备身份参数(设备三元组)

参数
参数来源
说明
是否保密
ProductID
产品详情页或设备详情页。
标识设备所属产品。
DeviceName
设备详情页。
标识产品下的具体设备。
DeviceSecret
设备详情页或动态注册。
用于生成 MQTT 认证签名。
注意:
ProductSecret 是产品级密钥,主要用于动态注册等产品级操作,不能代替 DeviceSecret 进行设备 MQTT 认证。

MQTT 连接参数

参数
取值或生成方式
说明
Broker Address
广州:${ProductID}.iotcloud.tencentdevices.com
曼谷:${ProductID}.ap-bangkok.iothub.tencentdevices.com
MQTT 服务器地址。
Broker Port
1883(通用)
8883(TLS+PSK 加密接入)
密钥认证设备接入端口。
Client ID
${ProductID}${DeviceName}
ProductID 与 DeviceName 直接拼接。
Username
${ClientID};${sdkappid};${connid};${expiry}
参与设备签名计算。
Password
${token};${签名算法}
使用 DeviceSecret 生成。
KeepAlive
0~900秒
MQTT 连接保活时间。
${}表示变量,不是实际的拼接字符。连接域名和端口应以设备所属地域及控制台当前信息为准。
各扩展字段含义如下:
字段
说明
sdkappid
固定填写12010126
connid
客户端生成的随机字符串,用于区分连接。
expiry
签名过期时间,使用 Unix 时间戳,单位为秒。
token
使用 DeviceSecret 对完整 Username 进行 HMAC 计算得到的摘要。
签名算法
支持hmacsha256hmacsha1,建议使用hmacsha256

使用 Python 连接平台

本节使用 Python 脚本连接物联网开发平台。当脚本返回认证成功且控制台设备状态显示为在线时,即表示设备密钥认证接入完成。
本示例仅验证设备认证和上线,不包含 Topic 发布、订阅及物模型消息通信。

前提条件

开始接入前,请确认已完成以下准备:
已创建认证方式为密钥认证的产品。
已在产品下创建设备
已获得设备的 MQTT 连接参数
本地环境已安装 Python 3
本地网络能够访问平台 MQTT 接入域名的 1883 端口。
如果需要设备在产测或首次启动阶段获取 DeviceSecret,请参见 密钥认证设备动态注册

获取设备连接参数

在控制台 获取设备三元组 并复制设备身份参数及 MQTT 连接参数。
控制台字段
脚本配置项
MQTT 服务器地址
Broker Address
端口号
Broker Port
Client ID
Client ID
Username
Username
Password
Password

准备运行环境

建议在虚拟环境中安装依赖和运行代码。
安装 Paho MQTT 客户端:
# Windows PowerShell
python -m pip install "paho-mqtt>=2.1,<3.0"

# Linux && macOS Shell
python3 -m pip install "paho-mqtt>=2.1,<3.0"
Paho MQTT 是 Python MQTT 客户端库。本示例使用 MQTT 3.1.1及 Callback API VERSION2。
安装完成后,可执行以下命令确认版本:
# Windows PowerShell
python -m pip show paho-mqtt

# Linux && macOS Shell
python3 -m pip show paho-mqtt

# 输出中的 Version 应为 2.1.0。

创建连接脚本

将以下代码保存为mqtt_connect.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import getpass
import sys
from importlib.metadata import PackageNotFoundError, version

try:
import paho.mqtt.client as mqtt
except ImportError:
mqtt = None


def required_input(prompt):
"""读取必填参数并清除首尾空格。"""
value = input(prompt).strip()
if not value:
raise ValueError("输入内容不能为空")
return value


def get_port():
"""读取并校验MQTT端口号。"""
port_text = input(
"端口号(直接回车使用1883):"
).strip()

if not port_text:
return 1883

try:
port = int(port_text)
except ValueError as exc:
raise ValueError("端口号必须是整数") from exc

if not 1 <= port <= 65535:
raise ValueError("端口号必须在1~65535范围内")

return port


def check_paho_version():
"""检查Paho MQTT是否安装且支持Callback API VERSION2。"""
install_command = (
f'"{sys.executable}" -m pip install "paho-mqtt==2.1.0"'
)

if mqtt is None:
raise ImportError(
"未安装Paho MQTT客户端。\\n"
f"请使用当前Python环境执行:\\n{install_command}"
)

try:
installed_version = version("paho-mqtt")
except PackageNotFoundError:
installed_version = "未知"

if not hasattr(mqtt, "CallbackAPIVersion"):
raise RuntimeError(
f"当前Paho MQTT版本为{installed_version},"
"不支持Callback API VERSION2。\\n"
f"请使用当前Python环境执行:\\n{install_command}"
)

print(f"Paho MQTT版本:{installed_version}")


def main():
check_paho_version()

print("\\n请输入设备详情页中的MQTT连接参数。")
print("输入内容仅在本次程序运行期间使用,不会保存到文件。\\n")

broker = required_input("MQTT服务器地址:")

if "://" in broker:
raise ValueError(
"MQTT服务器地址不能包含协议前缀,"
"请勿输入tcp://或mqtt://"
)

if any(char in broker for char in "${}"):
raise ValueError(
"MQTT服务器地址不能包含${},"
"请将${ProductID}替换为真实ProductID"
)

port = get_port()
client_id = required_input("ClientId:")
username = required_input("Username:")

# Password输入时不会显示在终端中。
password = getpass.getpass(
"Password(输入内容不会显示):"
).strip()

if not password:
raise ValueError("Password不能为空")

def on_connect(
client,
userdata,
connect_flags,
reason_code,
properties,
):
if reason_code == 0:
print("\\n认证成功,设备已连接物联网开发平台。")
print(f"MQTT服务器:{broker}")
print(f"端口号:{port}")
print("请前往控制台查看设备在线状态和上下线日志。")
else:
print(
f"\\nMQTT连接失败,返回码:{reason_code}。"
"\\n请检查ClientId、Username、Password及设备状态。"
)
client.disconnect()

def on_connect_fail(client, userdata):
print(
"\\n网络连接失败,请检查以下内容:"
f"\\n- MQTT服务器地址:{broker}"
f"\\n- 端口号:{port}"
"\\n- DNS解析及网络访问状态"
)

def on_disconnect(
client,
userdata,
disconnect_flags,
reason_code,
properties,
):
if reason_code != 0:
print(f"\\n连接异常断开,返回码:{reason_code}")

client = mqtt.Client(
callback_api_version=mqtt.CallbackAPIVersion.VERSION2,
client_id=client_id,
clean_session=True,
protocol=mqtt.MQTTv311,
)

client.username_pw_set(
username=username,
password=password,
)

client.on_connect = on_connect
client.on_connect_fail = on_connect_fail
client.on_disconnect = on_disconnect

# 不输出Username和Password等认证信息。
print("\\n连接配置:")
print(f"MQTT服务器:{broker}")
print(f"端口号:{port}")
print(f"ClientId:{client_id}")
print("\\n正在建立MQTT连接。")
print("程序将保持连接,按Ctrl+C退出。")

client.connect(
host=broker,
port=port,
keepalive=60,
)

try:
client.loop_forever()
finally:
client.disconnect()


if __name__ == "__main__":
try:
sys.exit(main())
except KeyboardInterrupt:
print("\\n用户终止连接。")
sys.exit(0)
except Exception as exc:
print(f"\\n运行失败:{exc}")
sys.exit(1)

运行连接脚本

执行:
# Windows PowerShell
python mqtt_connect.py

# Linux && macOS Shell
python3 mqtt_connect.py
# 运行成功后依次输入
MQTT服务器地址:
端口号(直接回车使用1883):
ClientId:
Username:
Password(输入内容不会显示):
连接成功时,程序输出类似:
正在连接:******.iotcloud.tencentdevices.com:1883
ClientId:******
程序将保持连接,按Ctrl+C退出。
认证成功,设备已连接物联网开发平台。
请前往控制台查看设备在线状态。
程序会持续运行并保持 MQTT 连接。需要断开连接时,按下Ctrl+C

验证设备上线

设备发起 MQTT 连接后,如需在控制台确认设备状态及查看上下线记录,请参见 设备上线和下线

问题排查

网络连接失败

检查以下内容:
Broker Address 是否与设备详情页一致。
端口号是否正确。
本地 DNS 是否能够解析 MQTT 服务器域名。
防火墙或网络策略是否限制目标域名和端口。
相关域名是否已加入白名单。

认证失败

检查以下内容:
ClientId、Username 和 Password 是否属于同一设备。
复制参数时是否包含多余空格或换行。
Username 中的 expiry 是否已过期。
是否使用了重新生成前的旧连接参数。
Broker 中的 ProductID 是否与设备所属产品一致。

出现 HMAC sign error

如果连接参数由设备自主生成,请检查:
ProductID 和 DeviceName 是否正确。
DeviceSecret 是否属于当前设备。
DeviceSecret 是否完成 Base64解码。
参与签名的 Username 是否与连接时使用的 Username 完全一致。
HMAC 算法是否与 Password 中的算法名称一致。
expiry 是否晚于当前设备时间。

脚本连接成功,但设备未显示在线

检查:
是否进入了正确的实例和设备。
ClientId 是否对应当前 DeviceName。
脚本是否仍在运行。
上下线日志中是否存在新的连接记录。
是否有另一个客户端使用相同 ClientId 建立连接。