
上周三晚上我对着终端愣了快四十分钟——刚写的Python物联网数据上报脚本,跑起来就跳Connection Refused: not authorised,错误码明明白白甩在日志里,连重试的机会都不给。
一开始我以为是复制设备三元组的时候粘错了字符,来回在物联网平台控制台和代码编辑器之间切了五六次,ProductKey、DeviceName、DeviceSecret逐个字符对,甚至删了测试设备重新建了一个,跑起来还是报同样的错。后来又怀疑是公司网络封了MQTT端口,掏出telnet测1883和8883端口都是通的,关了系统防火墙、换手机热点试了两轮,连接请求照样被服务端踢回来。
卡了快一小时才找到问题根因
翻到官方最新的文档才反应过来,之前搜的开源示例是好几年前的旧参数格式,阿里云MQTT的鉴权参数根本不是直接填三元组,要按指定规则拼接、签名,错一个字段就会被拒。照着文档捋了一遍正确的连接逻辑,调整之后一次就连通了,步骤其实很简单:
- 先安装依赖库:
pip install paho-mqtt - 按照规则拼接鉴权三要素,别抄网上旧示例的顺序:
- clientId格式:
[自定义客户端标识]|securemode=[模式值],signmethod=hmacsha256|,其中1883非加密端口模式值填3,8883 TLS加密端口填2 - username格式:
[DeviceName]&[ProductKey],注意顺序别写反 - password是HMAC-SHA256签名结果,签名原文要按固定字段顺序拼接,用DeviceSecret当密钥
- clientId格式:
签名生成和连接的核心代码可以直接复用:
import hmac
import hashlib
import paho.mqtt.client as mqtt
# 替换成自己设备的三元组
PRODUCT_KEY = "你的ProductKey"
DEVICE_NAME = "你的DeviceName"
DEVICE_SECRET = "你的DeviceSecret"
CLIENT_ID_TAG = "py_test_01" # 自定义的客户端标识,同设备下不要重复
def generate_mqtt_passwd():
# 注意:签名用的是自定义的短标识,不是拼接后的完整clientId
sign_content = f"clientId{CLIENT_ID_TAG}deviceName{DEVICE_NAME}productKey{PRODUCT_KEY}"
hmac_obj = hmac.new(
DEVICE_SECRET.encode("utf-8"),
sign_content.encode("utf-8"),
digestmod=hashlib.sha256
)
return hmac_obj.hexdigest()
client = mqtt.Client(client_id=f"{CLIENT_ID_TAG}|securemode=3,signmethod=hmacsha256|")
client.username_pw_set(
username=f"{DEVICE_NAME}&{PRODUCT_KEY}",
password=generate_mqtt_passwd()
)
# 公共实例接入域名格式:{PRODUCT_KEY}.iot-as-mqtt.[你的地域].aliyuncs.com
client.connect(f"{PRODUCT_KEY}.iot-as-mqtt.cn-shanghai.aliyuncs.com", 1883, 60)
client.loop_start()
几个容易被忽略的细节:
- 如果用的是企业实例,不要用公共实例的接入域名,要去控制台实例详情页找专属的MQTT接入地址
- 算签名的时候不要把拼接了securemode的完整clientId放进签名原文,签出来的结果肯定不对
- securemode的值和连接端口必须对应,不匹配的话就算签名正确也会被拒
哦对了,要是你按步骤写完还是连不上,记得先去控制台的日志服务看一眼鉴权失败的具体原因,比瞎改参数效率高多了。
评论一下?