基于MQTT协议的设备动态注册
在物联网平台控制台为产品开启动态注册功能后,直连设备可使用一型一密安全认证方式完成动态注册,通过MQTT通信协议连接物联网平台。设备先建立与物联网平台的连接,获取MQTT连接所需的设备证书,再断开连接,然后使用设备证书重新建立MQTT连接进行通信。本文介绍设备的动态注册流程。
前提条件
设备动态注册,是基于一型一密机制运作的,因此在此之前首先需要做的是:
- 创建产品
- 开启动态注册开关
- 将产品证书,MQTT连接地址信息配置到设备上
动态注册流程
sequenceDiagram
participant 设备
participant 物联网平台
设备->>物联网平台: 通过MQTT CONNECT报文发送动态注册请求
物联网平台-->>设备: 返回MQTT CONNECT ACK报文
物联网平台-->>设备: 注册成功,通过Topic: register/{produdctId}/{deviceId}/response返回认证参数
设备-->>设备: 保存认证参数
设备-->>物联网平台: 断开当前MQTT连接
Note over 物联网平台: 在此期间,云端忽略设备上行报文(除DISCONNECT报文)
设备->>物联网平台: 使用认证参数,通过MQTT CONNECT报文发送连接请求
物联网平台-->>设备: 返回MQTT CONNECT ACK报文
设备发送CONNECT报文,报文中包含动态注册参数,请求建立连接,CONNECT报文的动态注册参数:
mqttClientId:clientId+"|authType=xxxx,random=xxxx,signmethod=xxxx,deviceName=xxx|" mqttUserName: deviceId+"&"+productId mqttPassword:sign_hmac(productSecret,content)
参数说明:
mqttClientId参数 说明 clientId 客户端ID,可自定义,长度在64个字符内。建议使用设备的MAC地址或SN码,方便您识别区分不同的客户端 authType 一型一密认证方式,固定为register即可 random 随机数。您自定义随机数 signMethod 签名算法。目前支持hmacmd5、hmacsha1、hmacsha256 deviceName 设备名称,用于在注册设备时指定设备名称,不参与加签 mqttUserName
组成结构:deviceId+"&"+productId
示例:device1&al123456789mqttPassword
计算方法:sign_hmac(productSecret,content):::tip
其中,content的值是提交给服务器的必需参数和值(deviceId、productId、random)按照字母顺序排序、拼接(无拼接符号)的字符串。然后,将content的值通过mqttClientId中的signMethod指定的算法,使用产品的ProductSecret进行签名计算。示例:hmac_sha1(h1nQFYPZS0mW****, deviceIddevice1productIdal123456789random123)
:::物联网平台返回CONNECT ACK
- 返回0,表示设备动态注册成功
- 返回其他值,表示设备动态注册失败。根据返回的错误码,确定错误原因:
结果码 消息 说明 0 CONNECTION_ACCEPTED 动态注册成功。 3 SERVER_UNAVAILABLE 云端错误。请稍后再试。 4 CONNECTION_ACCEPTED 动态注册失败,鉴权未通过。请检查传入的mqttUserName和mqttPassword取值是否正确。 建立连接后,物联网平台通过推送证书的Topic,返回不同的认证参数。
推送Topic:register/{produdctId}/{deviceId}/response
报文:{ "deviceId": "device1", "deviceName": "设备名称", "deviceSecret": "3e4640b422d5231ad25c1bacf43127fd6e5192a523099f9fd4201d3d7ef723ae", "productId": "davKQYR6S5JHdKOozxUyZb27R" }
字段说明:
参数 说明 deviceId 注册成功的设备ID deviceName 注册成功的设备名称 deviceSecret 注册成功的设备密钥 productId 产品ID
加签代码示例(Java)
package org.example;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
public class Main {
/**
* mqtt认证处理
*/
public static void main(String[] args) throws Exception {
String mqttUserName;
String mqttClientId;
String mqttClientPassword;
var deviceId = "JXD20082652098";
var productId = "s0IVOpvPjKdTYsyxQfBAG9a6e";
var random = "123";
var plainPassword = String.format("deviceId%sproductId%srandom%s", deviceId, productId, random);
var productSecret = "bGqHdSKxjnld7uva";
var deviceName = "PAD一号";
// 不指定deviceName(设备名称)进行设备注册
mqttUserName = deviceId + "&" + productId;
mqttClientId = deviceId + "|securemode=2,authType=register,signmethod=hmacsha1,random=" + random + "|";
mqttClientPassword = hmac(plainPassword, productSecret, "hmacsha1", "%040x");
// 指定deviceName(设备名称)进行设备注册
mqttUserName = deviceId + "&" + productId;
mqttClientId = deviceId + "|securemode=2,authType=register,deviceName=" + deviceName + ",signmethod=hmacsha1,random=" + random + "|";
mqttClientPassword = hmac(plainPassword, productSecret, "hmacsha1", "%040x");
}
/**
* HMAC加密
*
* @param plainText 明文
* @param key 密钥
* @param algorithm 算法
* @param format 格式
* @return 密文
*/
private static String hmac(String plainText, String key, String algorithm, String format) throws Exception {
if (plainText == null || key == null) {
return null;
}
byte[] hmacResult = null;
Mac mac = Mac.getInstance(algorithm);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algorithm);
mac.init(secretKeySpec);
hmacResult = mac.doFinal(plainText.getBytes());
return String.format(format, new BigInteger(1, hmacResult));
}
}
修改于 2 个月前