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 4 import cn.idev.excel.annotation.ExcelProperty;
5 5 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
6 6 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
7   -import cn.iocoder.yudao.module.iot.enums.DictTypeConstants;
8 7 import io.swagger.v3.oas.annotations.media.Schema;
9 8 import lombok.Data;
10 9  
... ... @@ -80,10 +79,6 @@ public class IotDeviceRespVO {
80 79 @ExcelProperty("设备密钥")
81 80 private String deviceSecret;
82 81  
83   - @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")
84   - @ExcelProperty("认证类型(如一机一密、动态注册)")
85   - private String authType;
86   -
87 82 @Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
88 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 123 * 设备密钥,用于设备认证
124 124 */
125 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 810 @Override
811 811 public IotDeviceRegisterRespDTO registerDevice(IotDeviceRegisterReqDTO reqDTO) {
812 812 // 1.1 校验产品
813   - IotProductDO product = productService.getProductByProductKey(reqDTO.getProductKey());
  813 + IotProductDO product = TenantUtils.executeIgnore(() ->
  814 + productService.getProductByProductKey(reqDTO.getProductKey()));
814 815 if (product == null) {
815 816 throw exception(PRODUCT_NOT_EXISTS);
816 817 }
... ... @@ -822,21 +823,23 @@ public class IotDeviceServiceImpl implements IotDeviceService {
822 823 if (ObjUtil.notEqual(product.getProductSecret(), reqDTO.getProductSecret())) {
823 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 845 @Override
... ... @@ -845,7 +848,8 @@ public class IotDeviceServiceImpl implements IotDeviceService {
845 848 IotDeviceDO gatewayDevice = getSelf().getDeviceFromCache(reqDTO.getGatewayProductKey(), reqDTO.getGatewayDeviceName());
846 849  
847 850 // 2. 遍历注册每个子设备
848   - return registerSubDevices0(gatewayDevice, reqDTO.getSubDevices());
  851 + return TenantUtils.execute(gatewayDevice.getTenantId(), () ->
  852 + registerSubDevices0(gatewayDevice, reqDTO.getSubDevices()));
849 853 }
850 854  
851 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 68 @CacheEvict(value = RedisKeyConstants.PRODUCT, key = "#updateReqVO.id")
69 69 public void updateProduct(IotProductSaveReqVO updateReqVO) {
70 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 74 // 2. 更新
77 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 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 51 * 直连设备 Token:从 {@link #testAuth()} 方法获取后,粘贴到这里
62 52 */
63 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 61 public void testAuth() {
129 62 // 1.1 构建请求
130 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 65 IotDeviceAuthReqDTO authReqDTO = new IotDeviceAuthReqDTO()
133 66 .setClientId(authInfo.getClientId())
134 67 .setUsername(authInfo.getUsername())
... ... @@ -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 95  
96 96 // ===================== 拓扑管理测试 =====================
97 97  
98   - // TODO @芋艿:待测试
99   -
100 98 /**
101 99 * 添加子设备拓扑关系测试
102 100 * <p>
... ... @@ -222,7 +220,7 @@ public class IotGatewayDeviceHttpProtocolIntegrationTest {
222 220 // 1.2 构建请求参数
223 221 IotSubDeviceRegisterReqDTO subDevice = new IotSubDeviceRegisterReqDTO();
224 222 subDevice.setProductKey(SUB_DEVICE_PRODUCT_KEY);
225   - subDevice.setDeviceName(SUB_DEVICE_NAME);
  223 + subDevice.setDeviceName("mougezishebei");
226 224 String payload = JsonUtils.toJsonString(MapUtil.builder()
227 225 .put("id", IdUtil.fastSimpleUUID())
228 226 .put("method", IotDeviceMessageMethodEnum.SUB_DEVICE_REGISTER.getMethod())
... ...