一晃一年多没有做 OneNET 的相关开发了,最早做过 OneNET 的 MQTT 接入。自从上次用 OneNET 做机房环监后一直稳定运行,也没有继续拓展。

最近又需要对接 OneNET 做一个小项目了,故需要重新学习一下 OneNET,现在看了一下 OneNET 对接入能力进行了整合,原来的 EDP、MQTT、HTTP 协议的设备接入并入了多协议接入,在原 MQTT 协议的基础上,新增了 MQTT 物联网套件,不仅支持设备接入、数据存储、设备管理、设备命令,还支持了设备状态同步、消息分发、规则引擎等功能。

目前 MQTTs 使用 Token 进行鉴权验证,官网上提供了 Python 和 Java 两种语言的算法实现,本文提供了 NodeJS 和 PHP 两种语言的算法实现。

MQTT 物联网套件-Token 算法

res 参数说明

我们预期的 res 是一个字符串,以下是 res 资源格式说明(摘自 OneNET 文档):

场景 res 参数格式 示例 说明
API 访问 products/{pid} products/123123 配套使用产品 ak
设备连接 products/{pid}/devices/{device_name} products/123123/devices/mydev 配套使用设备 ak

PHP 实现

PHP 版本:PHP 7.x

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* @name: getToken
* @msg: MQTTs安全鉴权Token
* @param {string} res
* @param {string} accessKey
* @return: string
*/
function getToken($res, $access_key)
{
$version = '2018-10-31';
$et = time() + 3600; // 过期时间:一小时后token失效
$method = 'md5';
$key = base64_decode($access_key);
$org = $et . "\n" . $method . "\n" . $res . "\n" . $version;
// 签名
$sign_b = hash_hmac($method, $org, $key, true);
$sign = base64_encode($sign_b);
$sign = urlencode($sign);
$res = urlencode($res);
$token = 'version=' . $version . '&res=' . $res . '&et=' . $et . '&method=' . $method . '&sign=' . $sign;

return $token;
}

NodeJS 实现

NodeJS 版本:NodeJS 8.9

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const CryptoJS = require("crypto-js");
const urlencode = require("urlencode");

/**
* @name: getToken
* @msg: OneNET MQTTs Token 算法
* @param {*} res
* @param {*} access_key
* @return: token
*/
function getToken(res, access_key) {
var version = "2018-10-31"; // 参数组版本号
var et = String(parseInt(Date.now() / 1000) + 3600); // 访问过期时间 expirationTime (有效期为1小时)
var method = "md5";
// 对access_key进行base64解码
var key = CryptoJS.enc.Base64.parse(access_key);
// 计算sign
var org = et + "\n" + method + "\n" + res + "\n" + version;
var sign_b = CryptoJS.HmacMD5(org, key);
// 签名
var sign = CryptoJS.enc.Base64.stringify(sign_b);
// url 编码
sign = urlencode(sign);
res = urlencode(res);
// 拼接token
var token =
"version=" +
version +
"&res=" +
res +
"&et=" +
et +
"&method=" +
method +
"&sign=" +
sign;
return token;
}

如果需要更改 method 加密方法,CryptoJS.Hmac 语句也需要同步修改,对应关系见下表。

method CryptoJS.Hmac
md5 CryptoJS.HmacMD5
sha1 CryptoJS.HmacSHA1
sha256 CryptoJS.HmacSHA256