mirror of
https://gitee.com/zhijiantianya/ruoyi-vue-pro.git
synced 2026-03-22 05:07:17 +08:00
feat(iot):【网关设备:80%】动态注册的初步实现(已测试)
This commit is contained in:
@@ -4,7 +4,6 @@ import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
|||||||
import cn.idev.excel.annotation.ExcelProperty;
|
import cn.idev.excel.annotation.ExcelProperty;
|
||||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||||
import cn.iocoder.yudao.module.iot.enums.DictTypeConstants;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -80,10 +79,6 @@ public class IotDeviceRespVO {
|
|||||||
@ExcelProperty("设备密钥")
|
@ExcelProperty("设备密钥")
|
||||||
private String deviceSecret;
|
private String deviceSecret;
|
||||||
|
|
||||||
@Schema(description = "认证类型(如一机一密、动态注册)", example = "2")
|
|
||||||
@ExcelProperty("认证类型(如一机一密、动态注册)")
|
|
||||||
private String authType;
|
|
||||||
|
|
||||||
@Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
|
@Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
|
||||||
private String config;
|
private String config;
|
||||||
|
|
||||||
|
|||||||
@@ -123,11 +123,6 @@ public class IotDeviceDO extends TenantBaseDO {
|
|||||||
* 设备密钥,用于设备认证
|
* 设备密钥,用于设备认证
|
||||||
*/
|
*/
|
||||||
private String deviceSecret;
|
private String deviceSecret;
|
||||||
/**
|
|
||||||
* 认证类型(如一机一密、动态注册)
|
|
||||||
*/
|
|
||||||
// TODO @haohao:是不是要枚举哈
|
|
||||||
private String authType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备位置的纬度
|
* 设备位置的纬度
|
||||||
|
|||||||
@@ -810,7 +810,8 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||||||
@Override
|
@Override
|
||||||
public IotDeviceRegisterRespDTO registerDevice(IotDeviceRegisterReqDTO reqDTO) {
|
public IotDeviceRegisterRespDTO registerDevice(IotDeviceRegisterReqDTO reqDTO) {
|
||||||
// 1.1 校验产品
|
// 1.1 校验产品
|
||||||
IotProductDO product = productService.getProductByProductKey(reqDTO.getProductKey());
|
IotProductDO product = TenantUtils.executeIgnore(() ->
|
||||||
|
productService.getProductByProductKey(reqDTO.getProductKey()));
|
||||||
if (product == null) {
|
if (product == null) {
|
||||||
throw exception(PRODUCT_NOT_EXISTS);
|
throw exception(PRODUCT_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
@@ -822,21 +823,23 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||||||
if (ObjUtil.notEqual(product.getProductSecret(), reqDTO.getProductSecret())) {
|
if (ObjUtil.notEqual(product.getProductSecret(), reqDTO.getProductSecret())) {
|
||||||
throw exception(DEVICE_REGISTER_SECRET_INVALID);
|
throw exception(DEVICE_REGISTER_SECRET_INVALID);
|
||||||
}
|
}
|
||||||
// 1.4 校验设备是否已存在(已存在则不允许重复注册)
|
return TenantUtils.execute(product.getTenantId(), () -> {
|
||||||
IotDeviceDO device = getSelf().getDeviceFromCache(reqDTO.getProductKey(), reqDTO.getDeviceName());
|
// 1.4 校验设备是否已存在(已存在则不允许重复注册)
|
||||||
if (device != null) {
|
IotDeviceDO device = getSelf().getDeviceFromCache(reqDTO.getProductKey(), reqDTO.getDeviceName());
|
||||||
throw exception(DEVICE_REGISTER_ALREADY_EXISTS);
|
if (device != null) {
|
||||||
}
|
throw exception(DEVICE_REGISTER_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
// 2.1 自动创建设备
|
// 2.1 自动创建设备
|
||||||
IotDeviceSaveReqVO createReqVO = new IotDeviceSaveReqVO()
|
IotDeviceSaveReqVO createReqVO = new IotDeviceSaveReqVO()
|
||||||
.setDeviceName(reqDTO.getDeviceName())
|
.setDeviceName(reqDTO.getDeviceName())
|
||||||
.setProductId(product.getId());
|
.setProductId(product.getId());
|
||||||
device = createDevice0(createReqVO);
|
device = createDevice0(createReqVO);
|
||||||
log.info("[registerDevice][产品({}) 自动创建设备({})]",
|
log.info("[registerDevice][产品({}) 自动创建设备({})]",
|
||||||
reqDTO.getProductKey(), reqDTO.getDeviceName());
|
reqDTO.getProductKey(), reqDTO.getDeviceName());
|
||||||
// 2.2 返回设备密钥
|
// 2.2 返回设备密钥
|
||||||
return new IotDeviceRegisterRespDTO(device.getProductKey(), device.getDeviceName(), device.getDeviceSecret());
|
return new IotDeviceRegisterRespDTO(device.getProductKey(), device.getDeviceName(), device.getDeviceSecret());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -845,7 +848,8 @@ public class IotDeviceServiceImpl implements IotDeviceService {
|
|||||||
IotDeviceDO gatewayDevice = getSelf().getDeviceFromCache(reqDTO.getGatewayProductKey(), reqDTO.getGatewayDeviceName());
|
IotDeviceDO gatewayDevice = getSelf().getDeviceFromCache(reqDTO.getGatewayProductKey(), reqDTO.getGatewayDeviceName());
|
||||||
|
|
||||||
// 2. 遍历注册每个子设备
|
// 2. 遍历注册每个子设备
|
||||||
return registerSubDevices0(gatewayDevice, reqDTO.getSubDevices());
|
return TenantUtils.execute(gatewayDevice.getTenantId(), () ->
|
||||||
|
registerSubDevices0(gatewayDevice, reqDTO.getSubDevices()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -68,10 +68,8 @@ public class IotProductServiceImpl implements IotProductService {
|
|||||||
@CacheEvict(value = RedisKeyConstants.PRODUCT, key = "#updateReqVO.id")
|
@CacheEvict(value = RedisKeyConstants.PRODUCT, key = "#updateReqVO.id")
|
||||||
public void updateProduct(IotProductSaveReqVO updateReqVO) {
|
public void updateProduct(IotProductSaveReqVO updateReqVO) {
|
||||||
updateReqVO.setProductKey(null); // 不更新产品标识
|
updateReqVO.setProductKey(null); // 不更新产品标识
|
||||||
// 1.1 校验存在
|
// 1. 校验存在
|
||||||
IotProductDO iotProductDO = validateProductExists(updateReqVO.getId());
|
validateProductExists(updateReqVO.getId());
|
||||||
// 1.2 发布状态不可更新
|
|
||||||
validateProductStatus(iotProductDO);
|
|
||||||
|
|
||||||
// 2. 更新
|
// 2. 更新
|
||||||
IotProductDO updateObj = BeanUtils.toBean(updateReqVO, IotProductDO.class);
|
IotProductDO updateObj = BeanUtils.toBean(updateReqVO, IotProductDO.class);
|
||||||
|
|||||||
@@ -47,78 +47,11 @@ public class IotDirectDeviceHttpProtocolIntegrationTest {
|
|||||||
private static final String DEVICE_NAME = "small";
|
private static final String DEVICE_NAME = "small";
|
||||||
private static final String DEVICE_SECRET = "0baa4c2ecc104ae1a26b4070c218bdf3";
|
private static final String DEVICE_SECRET = "0baa4c2ecc104ae1a26b4070c218bdf3";
|
||||||
|
|
||||||
/**
|
|
||||||
* 产品密钥(从 iot_product 表的 product_secret 字段获取),用于动态注册
|
|
||||||
*/
|
|
||||||
private static final String PRODUCT_SECRET = "your_product_secret";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 动态注册的设备名称
|
|
||||||
*/
|
|
||||||
private static final String REGISTER_DEVICE_NAME = "test-register-device";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 直连设备 Token:从 {@link #testAuth()} 方法获取后,粘贴到这里
|
* 直连设备 Token:从 {@link #testAuth()} 方法获取后,粘贴到这里
|
||||||
*/
|
*/
|
||||||
private static final String TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9kdWN0S2V5IjoiNGF5bVpnT1RPT0NyREtSVCIsImV4cCI6MTc2OTMwNTA1NSwiZGV2aWNlTmFtZSI6InNtYWxsIn0.mf3MEATCn5bp6cXgULunZjs8d00RGUxj96JEz0hMS7k";
|
private static final String TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcm9kdWN0S2V5IjoiNGF5bVpnT1RPT0NyREtSVCIsImV4cCI6MTc2OTMwNTA1NSwiZGV2aWNlTmFtZSI6InNtYWxsIn0.mf3MEATCn5bp6cXgULunZjs8d00RGUxj96JEz0hMS7k";
|
||||||
|
|
||||||
// ===================== 动态注册测试 =====================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 直连设备动态注册测试(一型一密)
|
|
||||||
* <p>
|
|
||||||
* 使用产品密钥(productSecret)验证身份,成功后返回设备密钥(deviceSecret)
|
|
||||||
* <p>
|
|
||||||
* 注意:此接口不需要 Token 认证
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDeviceRegister() {
|
|
||||||
// 1.1 构建请求
|
|
||||||
String url = String.format("http://%s:%d/auth/register/device", SERVER_HOST, SERVER_PORT);
|
|
||||||
// 1.2 构建请求参数
|
|
||||||
IotDeviceRegisterReqDTO reqDTO = new IotDeviceRegisterReqDTO();
|
|
||||||
reqDTO.setProductKey(PRODUCT_KEY);
|
|
||||||
reqDTO.setDeviceName(REGISTER_DEVICE_NAME);
|
|
||||||
reqDTO.setProductSecret(PRODUCT_SECRET);
|
|
||||||
String payload = JsonUtils.toJsonString(reqDTO);
|
|
||||||
// 1.3 输出请求
|
|
||||||
log.info("[testDeviceRegister][请求 URL: {}]", url);
|
|
||||||
log.info("[testDeviceRegister][请求体: {}]", payload);
|
|
||||||
|
|
||||||
// 2.1 发送请求
|
|
||||||
String response = HttpUtil.post(url, payload);
|
|
||||||
// 2.2 输出结果
|
|
||||||
log.info("[testDeviceRegister][响应体: {}]", response);
|
|
||||||
log.info("[testDeviceRegister][成功后可使用返回的 deviceSecret 进行一机一密认证]");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 测试动态注册后使用 deviceSecret 进行认证
|
|
||||||
* <p>
|
|
||||||
* 此测试需要先执行 testDeviceRegister 获取 deviceSecret
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAuthAfterRegister() {
|
|
||||||
// 1.1 构建请求
|
|
||||||
String url = String.format("http://%s:%d/auth", SERVER_HOST, SERVER_PORT);
|
|
||||||
// TODO 将 testDeviceRegister 返回的 deviceSecret 填入此处
|
|
||||||
String deviceSecret = "返回的deviceSecret";
|
|
||||||
IotDeviceAuthUtils.AuthInfo authInfo = IotDeviceAuthUtils.getAuthInfo(PRODUCT_KEY, REGISTER_DEVICE_NAME, deviceSecret);
|
|
||||||
IotDeviceAuthReqDTO authReqDTO = new IotDeviceAuthReqDTO()
|
|
||||||
.setClientId(authInfo.getClientId())
|
|
||||||
.setUsername(authInfo.getUsername())
|
|
||||||
.setPassword(authInfo.getPassword());
|
|
||||||
String payload = JsonUtils.toJsonString(authReqDTO);
|
|
||||||
// 1.2 输出请求
|
|
||||||
log.info("[testAuthAfterRegister][请求 URL: {}]", url);
|
|
||||||
log.info("[testAuthAfterRegister][请求体: {}]", payload);
|
|
||||||
|
|
||||||
// 2.1 发送请求
|
|
||||||
String response = HttpUtil.post(url, payload);
|
|
||||||
// 2.2 输出结果
|
|
||||||
log.info("[testAuthAfterRegister][响应体: {}]", response);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===================== 认证测试 =====================
|
// ===================== 认证测试 =====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,7 +61,7 @@ public class IotDirectDeviceHttpProtocolIntegrationTest {
|
|||||||
public void testAuth() {
|
public void testAuth() {
|
||||||
// 1.1 构建请求
|
// 1.1 构建请求
|
||||||
String url = String.format("http://%s:%d/auth", SERVER_HOST, SERVER_PORT);
|
String url = String.format("http://%s:%d/auth", SERVER_HOST, SERVER_PORT);
|
||||||
IotDeviceAuthUtils.AuthInfo authInfo = IotDeviceAuthUtils.getAuthInfo(PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET);
|
IotDeviceAuthReqDTO authInfo = IotDeviceAuthUtils.getAuthInfo(PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET);
|
||||||
IotDeviceAuthReqDTO authReqDTO = new IotDeviceAuthReqDTO()
|
IotDeviceAuthReqDTO authReqDTO = new IotDeviceAuthReqDTO()
|
||||||
.setClientId(authInfo.getClientId())
|
.setClientId(authInfo.getClientId())
|
||||||
.setUsername(authInfo.getUsername())
|
.setUsername(authInfo.getUsername())
|
||||||
@@ -213,4 +146,34 @@ public class IotDirectDeviceHttpProtocolIntegrationTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===================== 动态注册测试 =====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直连设备动态注册测试(一型一密)
|
||||||
|
* <p>
|
||||||
|
* 使用产品密钥(productSecret)验证身份,成功后返回设备密钥(deviceSecret)
|
||||||
|
* <p>
|
||||||
|
* 注意:此接口不需要 Token 认证
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDeviceRegister() {
|
||||||
|
// 1.1 构建请求
|
||||||
|
String url = String.format("http://%s:%d/auth/register/device", SERVER_HOST, SERVER_PORT);
|
||||||
|
// 1.2 构建请求参数
|
||||||
|
IotDeviceRegisterReqDTO reqDTO = new IotDeviceRegisterReqDTO();
|
||||||
|
reqDTO.setProductKey(PRODUCT_KEY);
|
||||||
|
reqDTO.setDeviceName("test-" + System.currentTimeMillis());
|
||||||
|
reqDTO.setProductSecret("test-product-secret");
|
||||||
|
String payload = JsonUtils.toJsonString(reqDTO);
|
||||||
|
// 1.3 输出请求
|
||||||
|
log.info("[testDeviceRegister][请求 URL: {}]", url);
|
||||||
|
log.info("[testDeviceRegister][请求体: {}]", payload);
|
||||||
|
|
||||||
|
// 2.1 发送请求
|
||||||
|
String response = HttpUtil.post(url, payload);
|
||||||
|
// 2.2 输出结果
|
||||||
|
log.info("[testDeviceRegister][响应体: {}]", response);
|
||||||
|
log.info("[testDeviceRegister][成功后可使用返回的 deviceSecret 进行一机一密认证]");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,8 +95,6 @@ public class IotGatewayDeviceHttpProtocolIntegrationTest {
|
|||||||
|
|
||||||
// ===================== 拓扑管理测试 =====================
|
// ===================== 拓扑管理测试 =====================
|
||||||
|
|
||||||
// TODO @芋艿:待测试
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加子设备拓扑关系测试
|
* 添加子设备拓扑关系测试
|
||||||
* <p>
|
* <p>
|
||||||
@@ -222,7 +220,7 @@ public class IotGatewayDeviceHttpProtocolIntegrationTest {
|
|||||||
// 1.2 构建请求参数
|
// 1.2 构建请求参数
|
||||||
IotSubDeviceRegisterReqDTO subDevice = new IotSubDeviceRegisterReqDTO();
|
IotSubDeviceRegisterReqDTO subDevice = new IotSubDeviceRegisterReqDTO();
|
||||||
subDevice.setProductKey(SUB_DEVICE_PRODUCT_KEY);
|
subDevice.setProductKey(SUB_DEVICE_PRODUCT_KEY);
|
||||||
subDevice.setDeviceName(SUB_DEVICE_NAME);
|
subDevice.setDeviceName("mougezishebei");
|
||||||
String payload = JsonUtils.toJsonString(MapUtil.builder()
|
String payload = JsonUtils.toJsonString(MapUtil.builder()
|
||||||
.put("id", IdUtil.fastSimpleUUID())
|
.put("id", IdUtil.fastSimpleUUID())
|
||||||
.put("method", IotDeviceMessageMethodEnum.SUB_DEVICE_REGISTER.getMethod())
|
.put("method", IotDeviceMessageMethodEnum.SUB_DEVICE_REGISTER.getMethod())
|
||||||
|
|||||||
Reference in New Issue
Block a user