Commit e013b1add48585753874f8d6ce51d03299fc0f3a

Authored by YunaiV
1 parent b4ce72ea

feat(iot):【网关设备:80%】动态注册的初步实现(已测试)

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java
@@ -4,7 +4,6 @@ import cn.idev.excel.annotation.ExcelIgnoreUnannotated; @@ -4,7 +4,6 @@ import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
4 import cn.idev.excel.annotation.ExcelProperty; 4 import cn.idev.excel.annotation.ExcelProperty;
5 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; 5 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
6 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; 6 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
7 -import cn.iocoder.yudao.module.iot.enums.DictTypeConstants;  
8 import io.swagger.v3.oas.annotations.media.Schema; 7 import io.swagger.v3.oas.annotations.media.Schema;
9 import lombok.Data; 8 import lombok.Data;
10 9
@@ -80,10 +79,6 @@ public class IotDeviceRespVO { @@ -80,10 +79,6 @@ public class IotDeviceRespVO {
80 @ExcelProperty("设备密钥") 79 @ExcelProperty("设备密钥")
81 private String deviceSecret; 80 private String deviceSecret;
82 81
83 - @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")  
84 - @ExcelProperty("认证类型(如一机一密、动态注册)")  
85 - private String authType;  
86 -  
87 @Schema(description = "设备配置", example = "{\"abc\": \"efg\"}") 82 @Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
88 private String config; 83 private String config;
89 84
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
@@ -123,11 +123,6 @@ public class IotDeviceDO extends TenantBaseDO { @@ -123,11 +123,6 @@ public class IotDeviceDO extends TenantBaseDO {
123 * 设备密钥,用于设备认证 123 * 设备密钥,用于设备认证
124 */ 124 */
125 private String deviceSecret; 125 private String deviceSecret;
126 - /**  
127 - * 认证类型(如一机一密、动态注册)  
128 - */  
129 - // TODO @haohao:是不是要枚举哈  
130 - private String authType;  
131 126
132 /** 127 /**
133 * 设备位置的纬度 128 * 设备位置的纬度
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
@@ -810,7 +810,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -810,7 +810,8 @@ public class IotDeviceServiceImpl implements IotDeviceService {
810 @Override 810 @Override
811 public IotDeviceRegisterRespDTO registerDevice(IotDeviceRegisterReqDTO reqDTO) { 811 public IotDeviceRegisterRespDTO registerDevice(IotDeviceRegisterReqDTO reqDTO) {
812 // 1.1 校验产品 812 // 1.1 校验产品
813 - IotProductDO product = productService.getProductByProductKey(reqDTO.getProductKey()); 813 + IotProductDO product = TenantUtils.executeIgnore(() ->
  814 + productService.getProductByProductKey(reqDTO.getProductKey()));
814 if (product == null) { 815 if (product == null) {
815 throw exception(PRODUCT_NOT_EXISTS); 816 throw exception(PRODUCT_NOT_EXISTS);
816 } 817 }
@@ -822,21 +823,23 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -822,21 +823,23 @@ public class IotDeviceServiceImpl implements IotDeviceService {
822 if (ObjUtil.notEqual(product.getProductSecret(), reqDTO.getProductSecret())) { 823 if (ObjUtil.notEqual(product.getProductSecret(), reqDTO.getProductSecret())) {
823 throw exception(DEVICE_REGISTER_SECRET_INVALID); 824 throw exception(DEVICE_REGISTER_SECRET_INVALID);
824 } 825 }
825 - // 1.4 校验设备是否已存在(已存在则不允许重复注册)  
826 - IotDeviceDO device = getSelf().getDeviceFromCache(reqDTO.getProductKey(), reqDTO.getDeviceName());  
827 - if (device != null) {  
828 - throw exception(DEVICE_REGISTER_ALREADY_EXISTS);  
829 - } 826 + return TenantUtils.execute(product.getTenantId(), () -> {
  827 + // 1.4 校验设备是否已存在(已存在则不允许重复注册)
  828 + IotDeviceDO device = getSelf().getDeviceFromCache(reqDTO.getProductKey(), reqDTO.getDeviceName());
  829 + if (device != null) {
  830 + throw exception(DEVICE_REGISTER_ALREADY_EXISTS);
  831 + }
830 832
831 - // 2.1 自动创建设备  
832 - IotDeviceSaveReqVO createReqVO = new IotDeviceSaveReqVO()  
833 - .setDeviceName(reqDTO.getDeviceName())  
834 - .setProductId(product.getId());  
835 - device = createDevice0(createReqVO);  
836 - log.info("[registerDevice][产品({}) 自动创建设备({})]",  
837 - reqDTO.getProductKey(), reqDTO.getDeviceName());  
838 - // 2.2 返回设备密钥  
839 - return new IotDeviceRegisterRespDTO(device.getProductKey(), device.getDeviceName(), device.getDeviceSecret()); 833 + // 2.1 自动创建设备
  834 + IotDeviceSaveReqVO createReqVO = new IotDeviceSaveReqVO()
  835 + .setDeviceName(reqDTO.getDeviceName())
  836 + .setProductId(product.getId());
  837 + device = createDevice0(createReqVO);
  838 + log.info("[registerDevice][产品({}) 自动创建设备({})]",
  839 + reqDTO.getProductKey(), reqDTO.getDeviceName());
  840 + // 2.2 返回设备密钥
  841 + return new IotDeviceRegisterRespDTO(device.getProductKey(), device.getDeviceName(), device.getDeviceSecret());
  842 + });
840 } 843 }
841 844
842 @Override 845 @Override
@@ -845,7 +848,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { @@ -845,7 +848,8 @@ public class IotDeviceServiceImpl implements IotDeviceService {
845 IotDeviceDO gatewayDevice = getSelf().getDeviceFromCache(reqDTO.getGatewayProductKey(), reqDTO.getGatewayDeviceName()); 848 IotDeviceDO gatewayDevice = getSelf().getDeviceFromCache(reqDTO.getGatewayProductKey(), reqDTO.getGatewayDeviceName());
846 849
847 // 2. 遍历注册每个子设备 850 // 2. 遍历注册每个子设备
848 - return registerSubDevices0(gatewayDevice, reqDTO.getSubDevices()); 851 + return TenantUtils.execute(gatewayDevice.getTenantId(), () ->
  852 + registerSubDevices0(gatewayDevice, reqDTO.getSubDevices()));
849 } 853 }
850 854
851 @Override 855 @Override
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
@@ -68,10 +68,8 @@ public class IotProductServiceImpl implements IotProductService { @@ -68,10 +68,8 @@ public class IotProductServiceImpl implements IotProductService {
68 @CacheEvict(value = RedisKeyConstants.PRODUCT, key = "#updateReqVO.id") 68 @CacheEvict(value = RedisKeyConstants.PRODUCT, key = "#updateReqVO.id")
69 public void updateProduct(IotProductSaveReqVO updateReqVO) { 69 public void updateProduct(IotProductSaveReqVO updateReqVO) {
70 updateReqVO.setProductKey(null); // 不更新产品标识 70 updateReqVO.setProductKey(null); // 不更新产品标识
71 - // 1.1 校验存在  
72 - IotProductDO iotProductDO = validateProductExists(updateReqVO.getId());  
73 - // 1.2 发布状态不可更新  
74 - validateProductStatus(iotProductDO); 71 + // 1. 校验存在
  72 + validateProductExists(updateReqVO.getId());
75 73
76 // 2. 更新 74 // 2. 更新
77 IotProductDO updateObj = BeanUtils.toBean(updateReqVO, IotProductDO.class); 75 IotProductDO updateObj = BeanUtils.toBean(updateReqVO, IotProductDO.class);
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotDirectDeviceHttpProtocolIntegrationTest.java
@@ -48,77 +48,10 @@ public class IotDirectDeviceHttpProtocolIntegrationTest { @@ -48,77 +48,10 @@ public class IotDirectDeviceHttpProtocolIntegrationTest {
48 private static final String DEVICE_SECRET = "0baa4c2ecc104ae1a26b4070c218bdf3"; 48 private static final String DEVICE_SECRET = "0baa4c2ecc104ae1a26b4070c218bdf3";
49 49
50 /** 50 /**
51 - * 产品密钥(从 iot_product 表的 product_secret 字段获取),用于动态注册  
52 - */  
53 - private static final String PRODUCT_SECRET = "your_product_secret";  
54 -  
55 - /**  
56 - * 动态注册的设备名称  
57 - */  
58 - private static final String REGISTER_DEVICE_NAME = "test-register-device";  
59 -  
60 - /**  
61 * 直连设备 Token:从 {@link #testAuth()} 方法获取后,粘贴到这里 51 * 直连设备 Token:从 {@link #testAuth()} 方法获取后,粘贴到这里
62 */ 52 */
63 private static final String TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9kdWN0S2V5IjoiNGF5bVpnT1RPT0NyREtSVCIsImV4cCI6MTc2OTMwNTA1NSwiZGV2aWNlTmFtZSI6InNtYWxsIn0.mf3MEATCn5bp6cXgULunZjs8d00RGUxj96JEz0hMS7k"; 53 private static final String TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9kdWN0S2V5IjoiNGF5bVpnT1RPT0NyREtSVCIsImV4cCI6MTc2OTMwNTA1NSwiZGV2aWNlTmFtZSI6InNtYWxsIn0.mf3MEATCn5bp6cXgULunZjs8d00RGUxj96JEz0hMS7k";
64 54
65 - // ===================== 动态注册测试 =====================  
66 -  
67 - /**  
68 - * 直连设备动态注册测试(一型一密)  
69 - * <p>  
70 - * 使用产品密钥(productSecret)验证身份,成功后返回设备密钥(deviceSecret)  
71 - * <p>  
72 - * 注意:此接口不需要 Token 认证  
73 - */  
74 - @Test  
75 - public void testDeviceRegister() {  
76 - // 1.1 构建请求  
77 - String url = String.format("http://%s:%d/auth/register/device", SERVER_HOST, SERVER_PORT);  
78 - // 1.2 构建请求参数  
79 - IotDeviceRegisterReqDTO reqDTO = new IotDeviceRegisterReqDTO();  
80 - reqDTO.setProductKey(PRODUCT_KEY);  
81 - reqDTO.setDeviceName(REGISTER_DEVICE_NAME);  
82 - reqDTO.setProductSecret(PRODUCT_SECRET);  
83 - String payload = JsonUtils.toJsonString(reqDTO);  
84 - // 1.3 输出请求  
85 - log.info("[testDeviceRegister][请求 URL: {}]", url);  
86 - log.info("[testDeviceRegister][请求体: {}]", payload);  
87 -  
88 - // 2.1 发送请求  
89 - String response = HttpUtil.post(url, payload);  
90 - // 2.2 输出结果  
91 - log.info("[testDeviceRegister][响应体: {}]", response);  
92 - log.info("[testDeviceRegister][成功后可使用返回的 deviceSecret 进行一机一密认证]");  
93 - }  
94 -  
95 - /**  
96 - * 测试动态注册后使用 deviceSecret 进行认证  
97 - * <p>  
98 - * 此测试需要先执行 testDeviceRegister 获取 deviceSecret  
99 - */  
100 - @Test  
101 - public void testAuthAfterRegister() {  
102 - // 1.1 构建请求  
103 - String url = String.format("http://%s:%d/auth", SERVER_HOST, SERVER_PORT);  
104 - // TODO 将 testDeviceRegister 返回的 deviceSecret 填入此处  
105 - String deviceSecret = "返回的deviceSecret";  
106 - IotDeviceAuthUtils.AuthInfo authInfo = IotDeviceAuthUtils.getAuthInfo(PRODUCT_KEY, REGISTER_DEVICE_NAME, deviceSecret);  
107 - IotDeviceAuthReqDTO authReqDTO = new IotDeviceAuthReqDTO()  
108 - .setClientId(authInfo.getClientId())  
109 - .setUsername(authInfo.getUsername())  
110 - .setPassword(authInfo.getPassword());  
111 - String payload = JsonUtils.toJsonString(authReqDTO);  
112 - // 1.2 输出请求  
113 - log.info("[testAuthAfterRegister][请求 URL: {}]", url);  
114 - log.info("[testAuthAfterRegister][请求体: {}]", payload);  
115 -  
116 - // 2.1 发送请求  
117 - String response = HttpUtil.post(url, payload);  
118 - // 2.2 输出结果  
119 - log.info("[testAuthAfterRegister][响应体: {}]", response);  
120 - }  
121 -  
122 // ===================== 认证测试 ===================== 55 // ===================== 认证测试 =====================
123 56
124 /** 57 /**
@@ -128,7 +61,7 @@ public class IotDirectDeviceHttpProtocolIntegrationTest { @@ -128,7 +61,7 @@ public class IotDirectDeviceHttpProtocolIntegrationTest {
128 public void testAuth() { 61 public void testAuth() {
129 // 1.1 构建请求 62 // 1.1 构建请求
130 String url = String.format("http://%s:%d/auth", SERVER_HOST, SERVER_PORT); 63 String url = String.format("http://%s:%d/auth", SERVER_HOST, SERVER_PORT);
131 - IotDeviceAuthUtils.AuthInfo authInfo = IotDeviceAuthUtils.getAuthInfo(PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET); 64 + IotDeviceAuthReqDTO authInfo = IotDeviceAuthUtils.getAuthInfo(PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET);
132 IotDeviceAuthReqDTO authReqDTO = new IotDeviceAuthReqDTO() 65 IotDeviceAuthReqDTO authReqDTO = new IotDeviceAuthReqDTO()
133 .setClientId(authInfo.getClientId()) 66 .setClientId(authInfo.getClientId())
134 .setUsername(authInfo.getUsername()) 67 .setUsername(authInfo.getUsername())
@@ -213,4 +146,34 @@ public class IotDirectDeviceHttpProtocolIntegrationTest { @@ -213,4 +146,34 @@ public class IotDirectDeviceHttpProtocolIntegrationTest {
213 } 146 }
214 } 147 }
215 148
  149 + // ===================== 动态注册测试 =====================
  150 +
  151 + /**
  152 + * 直连设备动态注册测试(一型一密)
  153 + * <p>
  154 + * 使用产品密钥(productSecret)验证身份,成功后返回设备密钥(deviceSecret)
  155 + * <p>
  156 + * 注意:此接口不需要 Token 认证
  157 + */
  158 + @Test
  159 + public void testDeviceRegister() {
  160 + // 1.1 构建请求
  161 + String url = String.format("http://%s:%d/auth/register/device", SERVER_HOST, SERVER_PORT);
  162 + // 1.2 构建请求参数
  163 + IotDeviceRegisterReqDTO reqDTO = new IotDeviceRegisterReqDTO();
  164 + reqDTO.setProductKey(PRODUCT_KEY);
  165 + reqDTO.setDeviceName("test-" + System.currentTimeMillis());
  166 + reqDTO.setProductSecret("test-product-secret");
  167 + String payload = JsonUtils.toJsonString(reqDTO);
  168 + // 1.3 输出请求
  169 + log.info("[testDeviceRegister][请求 URL: {}]", url);
  170 + log.info("[testDeviceRegister][请求体: {}]", payload);
  171 +
  172 + // 2.1 发送请求
  173 + String response = HttpUtil.post(url, payload);
  174 + // 2.2 输出结果
  175 + log.info("[testDeviceRegister][响应体: {}]", response);
  176 + log.info("[testDeviceRegister][成功后可使用返回的 deviceSecret 进行一机一密认证]");
  177 + }
  178 +
216 } 179 }
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotGatewayDeviceHttpProtocolIntegrationTest.java
@@ -95,8 +95,6 @@ public class IotGatewayDeviceHttpProtocolIntegrationTest { @@ -95,8 +95,6 @@ public class IotGatewayDeviceHttpProtocolIntegrationTest {
95 95
96 // ===================== 拓扑管理测试 ===================== 96 // ===================== 拓扑管理测试 =====================
97 97
98 - // TODO @芋艿:待测试  
99 -  
100 /** 98 /**
101 * 添加子设备拓扑关系测试 99 * 添加子设备拓扑关系测试
102 * <p> 100 * <p>
@@ -222,7 +220,7 @@ public class IotGatewayDeviceHttpProtocolIntegrationTest { @@ -222,7 +220,7 @@ public class IotGatewayDeviceHttpProtocolIntegrationTest {
222 // 1.2 构建请求参数 220 // 1.2 构建请求参数
223 IotSubDeviceRegisterReqDTO subDevice = new IotSubDeviceRegisterReqDTO(); 221 IotSubDeviceRegisterReqDTO subDevice = new IotSubDeviceRegisterReqDTO();
224 subDevice.setProductKey(SUB_DEVICE_PRODUCT_KEY); 222 subDevice.setProductKey(SUB_DEVICE_PRODUCT_KEY);
225 - subDevice.setDeviceName(SUB_DEVICE_NAME); 223 + subDevice.setDeviceName("mougezishebei");
226 String payload = JsonUtils.toJsonString(MapUtil.builder() 224 String payload = JsonUtils.toJsonString(MapUtil.builder()
227 .put("id", IdUtil.fastSimpleUUID()) 225 .put("id", IdUtil.fastSimpleUUID())
228 .put("method", IotDeviceMessageMethodEnum.SUB_DEVICE_REGISTER.getMethod()) 226 .put("method", IotDeviceMessageMethodEnum.SUB_DEVICE_REGISTER.getMethod())