概述
设备向平台发起
HTTP/HTTPS
请求时,请求报文中需包含签名信息(X-TC-Signature)以验证请求者身份。签名步骤
设备请求报文示例:
curl -X POST https://ap-guangzhou.gateway.tencentdevices.com/device/register \\-H "Content-Type: application/json; charset=utf-8" \\-H "X-TC-Algorithm: hmacsha256" \\-H "X-TC-Timestamp: 155****065" \\-H "X-TC-Nonce: 5456" \\-H "X-TC-Signature: 2230eefd229f582d8b1b891af****b91597240707d778ab3738f756258d7652c" \\-d '{"ProductId":"ASJ****GX","DeviceName":"xyz"}'
1. 拼接签名字符串
StringToSign =HTTPRequestMethod + \\n +CanonicalHost + \\n +CanonicalURI + \\n +CanonicalQueryString + \\n +Algorithm + \\n +RequestTimestamp + \\n +Nonce + \\n +HashedCanonicalRequest
参数名称 | 描述 |
HTTPRequestMethod | HTTP 请求方式, 支持 POST。 |
CanonicalHost | HTTP 请求的 Host 地址。 |
CanonicalURI | HTTP 请求 URI 。例如 https://ap-guangzhou.gateway.tencentdevices.com/device/register 的 URI 为 /device/register 。 |
CanonicalQueryString | 发起 HTTP 请求 URL 中的查询字符串,对于 POST 请求,固定为空字符串 "" 。 |
Algorithm | 签名方法。目前支持 hmacsha256 和 hmacsha1。 |
RequestTimestamp | 请求时间戳,单位:秒。 |
Nonce | 随机数。 |
HashedCanonicalRequest | 请求正文 Hash 值。HTTP 请求正文做 SHA256 哈希,然后十六进制编码,最后编码串转换成小写字母。 |
根据以上的规则,示例中的规范签名串如下:
POSTap-guangzhou.gateway.tencentdevices.com/device/registerhmacsha256155****065545635e9c5b0e3ae67532d3c9f17ead6c902226****b1ff7f6e89887f1398934f064
2. 计算签名
使用密钥签名,包括产品级密钥和设备级密钥,伪代码如下:
Signature = Base64_Encode(HMAC_SHA256(SignSecret, StringToSign))
参数名称 | 描述 |
SignSecret | 签名密钥,如动态注册使用 ProductSecret,设备发布消息或上报日志则使用 psk。 |
StringToSign | 待签名的字符串。 |
使用证书签名,伪代码如下:
Signature = Base64_Encode(RSA_SHA256(PrivateKey, StringToSign))
参数名称 | 描述 |
PrivateKey | 证书私钥,如设备发布消息或上报日志则使用设备的 X509 私钥证书。 |
StringToSign | 待签名的字符串。 |
3. 组装请求报文
根据上述得到的签名串,最终完整的请求如下:
POST https://ap-guangzhou.gateway.tencentdevices.com/devregisterContent-Type: application/jsonHost: ap-guangzhou.gateway.tencentdevices.comX-TC-Algorithm: hmacsha256X-TC-Timestamp: 155****065X-TC-Nonce: 5456X-TC-Signature: 2230eefd229f582d8b1b891af71****1597240707d778ab3738f756258d7652c{"ProductId":"ASJ****GX","DeviceName":"xyz"}
示例代码
C 语言示例代码
./cmake_build.sh
编译成功后,按如下指令执行签名示例:
./out/bin/qcloud-dynreg-sign product_id product_secretkey device_name
Python3 示例代码
import hashlibimport randomimport timeimport hmacimport base64if __name__ == '__main__':sign_format = '%s\\n%s\\n%s\\n%s\\n%s\\n%d\\n%d\\n%s'url_format = '%s://ap-guangzhou.gateway.tencentdevices.com/device/register'request_format = "{\\"ProductId\\":\\"%s\\",\\"DeviceName\\":\\"%s\\"}"device_name = 'dev***'product_id = 'JCZ****KXS'product_secret = 'X42fPqw********94cY5sQ1Y'request_text = request_format % (product_id, device_name)request_hash = hashlib.sha256(request_text.encode("utf-8")).hexdigest()nonce = random.randrange(2147483647)timestamp = int(time.time())sign_content = sign_format % ("POST", "ap-guangzhou.gateway.tencentdevices.com","/device/register", "", "hmacsha256", timestamp,nonce, request_hash)print("\\nsign_content: \\n" + sign_content)sign_base64 = base64.b64encode(hmac.new(product_secret.encode("utf-8"),sign_content.encode("utf-8"), hashlib.sha256).digest())print("sign_base64: " + str(sign_base64))
Java 示例代码
package com.tencent.iot.hub.device.java.core.sign;import org.json.JSONException;import org.json.JSONObject;import org.junit.Test;import java.nio.charset.Charset;import java.security.InvalidKeyException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Base64;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import static junit.framework.TestCase.assertTrue;import static junit.framework.TestCase.fail;public class SignForHttpTest {private static final String HMAC_ALGO = "hmacsha256";@Testpublic void testSign() {try {JSONObject yourPayload = new JSONObject();String signature = getSignature("YourProductId", "YourDeviceName","YourDevicePsk", "YourTopicName", yourPayload, 0);System.out.println(signature);assertTrue(true);} catch (Exception e) {e.printStackTrace();fail();}}public static String getSignature(String productID, String deviceName, String devicePsk,String topicName, JSONObject payload, Integer qos) {int randNum = (int) (Math.random() * ((1 << 31) - 1));int timestamp = (int) (System.currentTimeMillis() / 1000);final JSONObject obj = new JSONObject();try {obj.put("ProductId", productID);obj.put("DeviceName", deviceName);obj.put("TopicName", topicName);obj.put("Payload", payload.toString());obj.put("Qos", qos);} catch (JSONException e) {e.printStackTrace();}String originRequest = obj.toString();String hashedRequest = "";try {MessageDigest digest = MessageDigest.getInstance("SHA-256");byte[] encodedhash = digest.digest(originRequest.getBytes(Charset.forName("UTF-8")));hashedRequest = HMACSHA256.bytesToHexString(encodedhash);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}@SuppressWarnings("DefaultLocale")String signSourceStr = String.format("%s\\n%s\\n%s\\n%s\\n%s\\n%d\\n%d\\n%s","POST","ap-guangzhou.gateway.tencentdevices.com","/device/publish","",HMAC_ALGO,timestamp,randNum,hashedRequest);return HMACSHA256.getSignature(signSourceStr.getBytes(), devicePsk.getBytes());}public static class HMACSHA256 {/*** 生成签名数据** @param data 待加密的数据* @param key 加密使用的key* @return 生成16进制编码的字符串*/public static String getSignature(byte[] data, byte[] key) {Mac mac;SecretKeySpec signKey = new SecretKeySpec(key, HMAC_ALGO);try {mac = Mac.getInstance(HMAC_ALGO);mac.init(signKey);byte[] rawHmac = mac.doFinal(data);return Base64.getEncoder().encodeToString(rawHmac);} catch (InvalidKeyException | NoSuchAlgorithmException 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();}}}