mirror of
https://github.com/YunaiV/ruoyi-vue-pro.git
synced 2026-04-19 16:18:37 +00:00
feat(iot):【网关设备:70%】动态注册的初步实现(未测试),基于 stateful-sauteeing-pillow.md 规划
This commit is contained in:
@@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceGetReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.topic.auth.IotDeviceRegisterRespDTO;
|
||||
|
||||
/**
|
||||
* IoT 设备通用 API
|
||||
@@ -28,4 +30,12 @@ public interface IotDeviceCommonApi {
|
||||
*/
|
||||
CommonResult<IotDeviceRespDTO> getDevice(IotDeviceGetReqDTO infoReqDTO);
|
||||
|
||||
/**
|
||||
* 设备动态注册(一型一密)
|
||||
*
|
||||
* @param reqDTO 动态注册请求
|
||||
* @return 注册结果(包含 DeviceSecret)
|
||||
*/
|
||||
CommonResult<IotDeviceRegisterRespDTO> registerDevice(IotDeviceRegisterReqDTO reqDTO);
|
||||
|
||||
}
|
||||
|
||||
@@ -33,9 +33,10 @@ public enum IotDeviceMessageMethodEnum implements ArrayValuable<String> {
|
||||
TOPO_CHANGE("thing.topo.change", "拓扑关系变更通知", false),
|
||||
|
||||
// ========== 设备注册 ==========
|
||||
// 可参考:https://help.aliyun.com/zh/iot/user-guide/register-devices
|
||||
// 可参考:https://help.aliyun.com/zh/iot/user-guide/unique-certificate-per-product-verification
|
||||
|
||||
SUB_DEVICE_REGISTER("thing.sub.register", "子设备动态注册", true),
|
||||
DEVICE_REGISTER("thing.auth.register", "设备动态注册", true),
|
||||
SUB_DEVICE_REGISTER("thing.auth.register.sub", "子设备动态注册", true),
|
||||
|
||||
// ========== 设备属性 ==========
|
||||
// 可参考:https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.iot.core.topic.auth;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT 设备动态注册 Request DTO
|
||||
* <p>
|
||||
* 用于直连设备/网关的一型一密动态注册:使用 ProductSecret 验证签名,返回 DeviceSecret
|
||||
*
|
||||
* @author 芋道源码
|
||||
* @see <a href="https://help.aliyun.com/zh/iot/user-guide/unique-certificate-per-product-verification">阿里云 - 一型一密</a>
|
||||
*/
|
||||
@Data
|
||||
public class IotDeviceRegisterReqDTO {
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
@NotEmpty(message = "产品标识不能为空")
|
||||
private String productKey;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
@NotEmpty(message = "设备名称不能为空")
|
||||
private String deviceName;
|
||||
|
||||
// TODO @AI:可以去掉 random 字段;
|
||||
/**
|
||||
* 随机数,用于签名
|
||||
*/
|
||||
@NotEmpty(message = "随机数不能为空")
|
||||
private String random;
|
||||
|
||||
// TODO @AI:看起来,是直接带 productSecret 阿里云上,你在检查下!
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
@NotEmpty(message = "签名不能为空")
|
||||
private String sign;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cn.iocoder.yudao.module.iot.core.topic.auth;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* IoT 设备动态注册 Response DTO
|
||||
* <p>
|
||||
* 用于直连设备/网关的一型一密动态注册响应
|
||||
*
|
||||
* @author 芋道源码
|
||||
* @see <a href="https://help.aliyun.com/zh/iot/user-guide/unique-certificate-per-product-verification">阿里云 - 一型一密</a>
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IotDeviceRegisterRespDTO {
|
||||
|
||||
/**
|
||||
* 产品标识
|
||||
*/
|
||||
private String productKey;
|
||||
|
||||
/**
|
||||
* 设备名称
|
||||
*/
|
||||
private String deviceName;
|
||||
|
||||
/**
|
||||
* 设备密钥
|
||||
*/
|
||||
private String deviceSecret;
|
||||
|
||||
}
|
||||
@@ -6,10 +6,12 @@ import lombok.Data;
|
||||
/**
|
||||
* IoT 子设备动态注册 Request DTO
|
||||
* <p>
|
||||
* 用于 thing.sub.register 消息的 params 数组元素
|
||||
* 用于 thing.auth.register.sub 消息的 params 数组元素
|
||||
*
|
||||
* 特殊:网关子设备的动态注册,必须已经创建好该网关子设备(不然哪来的 {@link #deviceName} 字段)。更多的好处,是设备不用提前烧录 deviceSecret 密钥。
|
||||
*
|
||||
* @author 芋道源码
|
||||
* @see <a href="http://help.aliyun.com/zh/marketplace/dynamic-registration-of-sub-devices">阿里云 - 动态注册子设备</a>
|
||||
* @see <a href="https://help.aliyun.com/zh/iot/user-guide/register-devices">阿里云 - 动态注册子设备</a>
|
||||
*/
|
||||
@Data
|
||||
public class IotSubDeviceRegisterReqDTO {
|
||||
|
||||
@@ -7,10 +7,10 @@ import lombok.NoArgsConstructor;
|
||||
/**
|
||||
* IoT 子设备动态注册 Response DTO
|
||||
* <p>
|
||||
* 用于 thing.sub.register 响应的设备信息
|
||||
* 用于 thing.auth.register.sub 响应的设备信息
|
||||
*
|
||||
* @author 芋道源码
|
||||
* @see <a href="http://help.aliyun.com/zh/marketplace/dynamic-registration-of-sub-devices">阿里云 - 动态注册子设备</a>
|
||||
* @see <a href="https://help.aliyun.com/zh/iot/user-guide/register-devices">阿里云 - 动态注册子设备</a>
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.iot.core.util;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import cn.hutool.crypto.digest.HmacAlgorithm;
|
||||
@@ -87,4 +88,62 @@ public class IotDeviceAuthUtils {
|
||||
return new DeviceInfo().setProductKey(usernameParts[1]).setDeviceName(usernameParts[0]);
|
||||
}
|
||||
|
||||
// ========== 动态注册相关方法 ==========
|
||||
|
||||
// TODO @AI:想了下,还是放回到对应的 productService、deviceService 更合适;
|
||||
|
||||
/**
|
||||
* 生成产品密钥
|
||||
*
|
||||
* @return 产品密钥(UUID)
|
||||
*/
|
||||
public static String generateProductSecret() {
|
||||
return IdUtil.fastSimpleUUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成设备密钥
|
||||
*
|
||||
* @return 设备密钥(UUID)
|
||||
*/
|
||||
public static String generateDeviceSecret() {
|
||||
return IdUtil.fastSimpleUUID();
|
||||
}
|
||||
|
||||
// TODO @AI:去掉 random;
|
||||
/**
|
||||
* 计算动态注册签名
|
||||
* <p>
|
||||
* 参考阿里云规范,参数按字典序排列拼接
|
||||
*
|
||||
* @param productSecret 产品密钥
|
||||
* @param productKey 产品标识
|
||||
* @param deviceName 设备名称
|
||||
* @param random 随机数
|
||||
* @return 签名
|
||||
* @see <a href="https://help.aliyun.com/zh/iot/user-guide/unique-certificate-per-product-verification">一型一密</a>
|
||||
*/
|
||||
public static String buildRegisterSign(String productSecret, String productKey, String deviceName, String random) {
|
||||
String content = "deviceName" + deviceName + "productKey" + productKey + "random" + random;
|
||||
return DigestUtil.hmac(HmacAlgorithm.HmacSHA256, StrUtil.utf8Bytes(productSecret))
|
||||
.digestHex(content);
|
||||
}
|
||||
|
||||
// TODO @AI:是不是调用方自己验证就好了,不要这里面抽;
|
||||
/**
|
||||
* 验证动态注册签名
|
||||
*
|
||||
* @param productSecret 产品密钥
|
||||
* @param productKey 产品标识
|
||||
* @param deviceName 设备名称
|
||||
* @param random 随机数
|
||||
* @param sign 待验证的签名
|
||||
* @return 是否验证通过
|
||||
*/
|
||||
public static boolean verifyRegisterSign(String productSecret, String productKey,
|
||||
String deviceName, String random, String sign) {
|
||||
String expectedSign = buildRegisterSign(productSecret, productKey, deviceName, random);
|
||||
return expectedSign.equals(sign);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user