产品动态
${productId}/${deviceName}/control订阅。${productId}/${deviceName}/event发布。${productId}/${deviceName}/data订阅和发布。$shadow/operation/${productId}/${deviceName}发布。通过包体内部 type 来区分:update/get,分别对应设备影子文档的更新和拉取等操作。$shadow/operation/result/${productId}/${deviceName}订阅。通过包体内部 type 来区分:update/get/delta,type 为 update/get 分别对应设备影子文档的更新和拉取等操作的结果;当用户通过 restAPI 修改设备影子文档后,服务端将通过该 topic 发布消息,其中 type 为 delta。$ota/report/${productID}/${deviceName}发布。设备上报版本号及下载、升级进度到云端。$ota/update/${productID}/${deviceName}订阅。设备接收云端的升级消息。接入认证方式 | 连接域名及端口 | Connect报文参数 |
证书认证 | MQTT 服务器连接地址,广州域设备填入:${productId}.iotcloud.tencentdevices.com,这里 ${productId}为变量参数,用户需填入创建产品时自动生成的产品 ID,例如 1A17RZR3XX.iotcloud.tencentdevices.com;端口:8883 | KeepAlive:保持连接的时间,取值范围为0 - 900s。若超过1.5倍 KeepAlive 时长物联网平台仍没收到客户端的数据,则平台将断开与客户端的连接; ClientId:${productId}${deviceName},产品 ID 和设备名的组合字符串; UserName: ${productId}${deviceName};${sdkappid};${connid};${expiry},详情见下文中基于 MQTT 的签名认证接入指引 username 部分;PassWord:密码(可赋任意值)。 |
密钥认证 | MQTT 服务器连接地址与证书认证一致;端口:1883 | KeepAlive:保持连接的时间,取值范围为0-900s; ClientId:${productId}${deviceName}; UserName: ${productId}${deviceName};${sdkappid};${connid};${expiry},详情见下文中基于 MQTT 的签名认证接入指引 username 部分;PassWord:密码,详情见下文中基于 MQTT 的签名认证接入指引 password 部分。 |
username 字段的格式为:${productId}${deviceName};${sdkappid};${connid};${expiry}注意:${} 表示变量,并非特定的拼接符号。
password 字段格式为:${token};hmac 签名方法其中 hmac 签名方法字段填写第三步用到的摘要算法,可选的值有 hmacsha256 和 hmacsha1。
#!/usr/bin/python# -*- coding: UTF-8 -*-import base64import hashlibimport hmacimport randomimport stringimport timeimport sys# 生成指定长度的随机字符串def RandomConnid(length):return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length))# 生成接入物联网通信平台需要的各参数def IotHmac(productID, devicename, devicePsk):# 1. 生成 connid 为一个随机字符串,方便后台定位问题connid = RandomConnid(5)# 2. 生成过期时间,表示签名的过期时间,从纪元1970年1月1日 00:00:00 UTC 时间至今秒数的 UTF8 字符串expiry = int(time.time()) + 60 * 60# 3. 生成 MQTT 的 clientid 部分, 格式为 ${productid}${devicename}clientid = "{}{}".format(productID, devicename)# 4. 生成 MQTT 的 username 部分, 格式为 ${clientid};${sdkappid};${connid};${expiry}username = "{};12010126;{};{}".format(clientid, connid, expiry)# 5. 对 username 进行签名,生成tokensecret_key = devicePsk.encode('utf-8') # convert to bytesdata_to_sign = username.encode('utf-8') # convert to bytessecret_key = base64.b64decode(secret_key) # this is still bytestoken = hmac.new(secret_key, data_to_sign, digestmod=hashlib.sha256).hexdigest()# 6. 根据物联网通信平台规则生成 password 字段password = "{};{}".format(token, "hmacsha256")return {"clientid" : clientid,"username" : username,"password" : password}if __name__ == '__main__':print(IotHmac(sys.argv[1], sys.argv[2], sys.argv[3]))
python3 IotHmac.py "YOUR_PRODUCTID" "YOUR_DEVICENAME" "YOUR_PSK"
import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import java.util.*;public class IotHmac {public static void main(String[] args) throws Exception {System.out.println(IotHmac("YOUR_PRODUCTID","YOUR_DEVICENAME","YOUR_PSK"));}public static Map<String, String> IotHmac(String productID, String devicename, StringdevicePsk) throws Exception {final Base64.Decoder decoder = Base64.getDecoder();//1. 生成 connid 为一个随机字符串,方便后台定位问题String connid = HMACSHA256.getRandomString2(5);//2. 生成过期时间,表示签名的过期时间,从纪元1970年1月1日 00:00:00 UTC 时间至今秒数的 UTF8 字符串Long expiry = Calendar.getInstance().getTimeInMillis()/1000 +600;//3. 生成 MQTT 的 clientid 部分, 格式为 ${productid}${devicename}String clientid = productID+devicename;//4. 生成 MQTT 的 username 部分, 格式为 ${clientid};${sdkappid};${connid};${expiry}String username = clientid+";"+"12010126;"+connid+";"+expiry;//5. 对 username 进行签名,生成token、根据物联网通信平台规则生成 password 字段String password = HMACSHA256.getSignature(username.getBytes(), decoder.decode(devicePsk)) + ";hmacsha256";Map<String,String> map = new HashMap<>();map.put("clientid",clientid);map.put("username",username);map.put("password",password);return map;}public static class HMACSHA256 {private static final String HMAC_SHA256 = "HmacSHA256";/*** 生成签名数据** @param data 待加密的数据* @param key 加密使用的key* @return 生成16进制编码的字符串*/public static String getSignature(byte[] data, byte[] key) {try {SecretKeySpec signingKey = new SecretKeySpec(key, HMAC_SHA256);Mac mac = Mac.getInstance(HMAC_SHA256);mac.init(signingKey);byte[] rawHmac = mac.doFinal(data);return bytesToHexString(rawHmac);}catch (Exception e) {e.printStackTrace();}return null;}/*** byte[]数组转换为16进制的字符串** @param bytes 要转换的字节数组* @return 转换后的结果*/private static String bytesToHexString(byte[] bytes) {StringBuilder sb = new StringBuilder();for (int i = 0; i < bytes.length; i++) {String hex = Integer.toHexString(0xFF & bytes[i]);if (hex.length() == 1) {sb.append('0');}sb.append(hex);}return sb.toString();}public static String getRandomString2(int length) {Random random = new Random();StringBuffer sb = new StringBuffer();for (int i = 0; i < length; i++) {int number = random.nextInt(3);long result = 0;switch (number) {case 0:result = Math.round(Math.random() * 25 + 65);sb.append(String.valueOf((char) result));break;case 1:result = Math.round(Math.random() * 25 + 97);sb.append(String.valueOf((char) result));break;case 2:sb.append(String.valueOf(new Random().nextInt(10)));break;}}return sb.toString();}}}
// 下面为node引入方式,浏览器的话,使用对应的方式引入crypto-js库const crypto = require('crypto-js')// 产生随机数的函数const randomString = (len) => {len = len || 32;var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';var maxPos = chars.length;var pwd = '';for (let i = 0; i < len; i++) {pwd += chars.charAt(Math.floor(Math.random() * maxPos));}return pwd;}// 需要产品id,设备名和设备密钥const productId = 'YOUR_PRODUCTID';const deviceName = 'YOUR_DEVICENAME';const devicePsk = 'YOUR_PSK';// 1. 生成 connid 为一个随机字符串,方便后台定位问题const connid = randomString(5);// 2. 生成过期时间,表示签名的过期时间,从纪元1970年1月1日 00:00:00 UTC 时间至今秒数的 UTF8 字符串const expiry = Math.round(new Date().getTime() / 1000) + 3600 * 24;// 3. 生成 MQTT 的 clientid 部分, 格式为 ${productid}${devicename}const clientId = productId + deviceName;// 4. 生成 MQTT 的 username 部分, 格式为 ${clientid};${sdkappid};${connid};${expiry}const userName = `${clientId};12010126;${connid};${expiry}`;//5. 对 username 进行签名,生成token、根据物联网通信平台规则生成 password 字段const rawKey = crypto.enc.Base64.parse(devicePsk); // 对设备密钥进行base64解码const token = crypto.HmacSHA256(userName, rawKey);const password = token.toString(crypto.enc.Hex) + ";hmacsha256";console.log(`userName:${userName}\\npassword:${password}`);
#include "limits.h"#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include "HAL_Platform.h"#include "utils_base64.h"#include "utils_hmac.h"/* Max size of base64 encoded PSK = 64, after decode: 64/4*3 = 48*/#define DECODE_PSK_LENGTH 48/* MAX valid time when connect to MQTT server. 0: always valid *//* Use this only if the device has accurate UTC time. Otherwise, set to 0 */#define MAX_ACCESS_EXPIRE_TIMEOUT (0)/* Max size of conn Id */#define MAX_CONN_ID_LEN (6)/* IoT C-SDK APPID */#define QCLOUD_IOT_DEVICE_SDK_APPID "21****06"#define QCLOUD_IOT_DEVICE_SDK_APPID_LEN (sizeof(QCLOUD_IOT_DEVICE_SDK_APPID) - 1)static void HexDump(char *pData, uint16_t len){int i;for (i = 0; i < len; i++) {HAL_Printf("0x%02.2x ", (unsigned char)pData[i]);}HAL_Printf("\\n");}static void get_next_conn_id(char *conn_id){int i;srand((unsigned)HAL_GetTimeMs());for (i = 0; i < MAX_CONN_ID_LEN - 1; i++) {int flag = rand() % 3;switch (flag) {case 0:conn_id[i] = (rand() % 26) + 'a';break;case 1:conn_id[i] = (rand() % 26) + 'A';break;case 2:conn_id[i] = (rand() % 10) + '0';break;}}conn_id[MAX_CONN_ID_LEN - 1] = '\\0';}int main(int argc, char **argv){char *product_id = NULL;char *device_name = NULL;char *device_secret = NULL;char *username = NULL;int username_len = 0;char conn_id[MAX_CONN_ID_LEN];char password[51] = {0};char username_sign[41] = {0};char psk_base64decode[DECODE_PSK_LENGTH];size_t psk_base64decode_len = 0;long cur_timestamp = 0;if (argc != 4) {HAL_Printf("please ./qcloud-mqtt-sign product_id device_name device_secret\\r\\n");return -1;}product_id = argv[1];device_name = argv[2];device_secret = argv[3];/* first device_secret base64 decode */qcloud_iot_utils_base64decode((unsigned char *)psk_base64decode, DECODE_PSK_LENGTH, &psk_base64decode_len,(unsigned char *)device_secret, strlen(device_secret));HAL_Printf("device_secret base64 decode:");HexDump(psk_base64decode, psk_base64decode_len);/* second create mqtt username* [productdevicename;appid;randomconnid;timestamp] */cur_timestamp = HAL_Timer_current_sec() + MAX_ACCESS_EXPIRE_TIMEOUT / 1000;if (cur_timestamp <= 0 || MAX_ACCESS_EXPIRE_TIMEOUT <= 0) {cur_timestamp = LONG_MAX;}// 20 for timestampe length & delimiterusername_len = strlen(product_id) + strlen(device_name) + QCLOUD_IOT_DEVICE_SDK_APPID_LEN + MAX_CONN_ID_LEN + 20;username = (char *)HAL_Malloc(username_len);if (username == NULL) {HAL_Printf("malloc username failed!\\r\\n");return -1;}get_next_conn_id(conn_id);HAL_Snprintf(username, username_len, "%s%s;%s;%s;%ld", product_id, device_name, QCLOUD_IOT_DEVICE_SDK_APPID,conn_id, cur_timestamp);/* third use psk_base64decode hamc_sha1 calc mqtt username sign crate mqtt* password */utils_hmac_sha1(username, strlen(username), username_sign, psk_base64decode, psk_base64decode_len);HAL_Printf("username sign: %s\\r\\n", username_sign);HAL_Snprintf(password, 51, "%s;hmacsha1", username_sign);HAL_Printf("Client ID: %s%s\\r\\n", product_id, device_name);HAL_Printf("username : %s\\r\\n", username);HAL_Printf("password : %s\\r\\n", password);HAL_Free(username);return 0;}
文档反馈