Commit e013b1add48585753874f8d6ce51d03299fc0f3a
1 parent
b4ce72ea
feat(iot):【网关设备:80%】动态注册的初步实现(已测试)
Showing
6 changed files
with
54 additions
and
101 deletions
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
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()) | ... | ... |