Browse Source

feat:【IoT 物联网】增加网关 HTTP 协议的鉴权,基于 JWT 轻量级

YunaiV 5 tháng trước cách đây
mục cha
commit
643cc4cfd2
40 tập tin đã thay đổi với 793 bổ sung498 xóa
  1. 13 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
  2. 0 30
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java
  3. 0 4
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/package-info.java
  4. 0 6
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
  5. 0 18
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
  6. 37 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java
  7. 0 30
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java
  8. 1 3
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java
  9. 1 14
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
  10. 12 11
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java
  11. 0 29
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/config/SecurityConfiguration.java
  12. 0 4
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/core/package-info.java
  13. 9 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
  14. 37 9
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java
  15. 0 8
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java
  16. 0 36
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java
  17. 0 69
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java
  18. 11 1
      yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/biz/IotDeviceCommonApi.java
  19. 3 5
      yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/biz/dto/IotDeviceAuthReqDTO.java
  20. 85 0
      yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceAuthUtils.java
  21. 1 1
      yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java
  22. 5 0
      yudao-module-iot/yudao-module-iot-gateway/pom.xml
  23. 2 3
      yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java
  24. 30 2
      yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java
  25. 16 0
      yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/enums/ErrorCodeConstants.java
  26. 4 5
      yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpUpstreamProtocol.java
  27. 98 0
      yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAbstractHandler.java
  28. 84 0
      yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAuthHandler.java
  29. 26 55
      yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java
  30. 37 0
      yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/auth/IotDeviceTokenService.java
  31. 79 0
      yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/auth/IotDeviceTokenServiceImpl.java
  32. 58 0
      yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/IotDeviceClientServiceImpl.java
  33. 4 0
      yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml
  34. 139 0
      yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/service/auth/IotDeviceTokenServiceImplTest.java
  35. 0 25
      yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonAutoConfiguration.java
  36. 0 26
      yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/upstream/IotDeviceUpstreamClient.java
  37. 0 56
      yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/util/IotNetComponentCommonUtils.java
  38. 0 1
      yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  39. 1 1
      yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-emqx/src/main/java/cn/iocoder/yudao/module/iot/net/component/emqx/upstream/router/IotDeviceAuthVertxHandler.java
  40. 0 46
      yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/upstream/IotComponentUpstreamClient.java

+ 13 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.common.util.date;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DatePattern;
 import cn.hutool.core.date.LocalDateTimeUtil;
+import cn.hutool.core.date.TemporalAccessorUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
@@ -312,4 +313,16 @@ public class LocalDateTimeUtils {
         }
     }
 
+    /**
+     * 将给定的 {@link LocalDateTime} 转换为自 Unix 纪元时间(1970-01-01T00:00:00Z)以来的秒数。
+     *
+     * @param sourceDateTime 需要转换的本地日期时间,不能为空
+     * @return 自 1970-01-01T00:00:00Z 起的秒数(epoch second)
+     * @throws NullPointerException 如果 {@code sourceDateTime} 为 {@code null}
+     * @throws DateTimeException 如果转换过程中发生时间超出范围或其他时间处理异常
+     */
+    public static Long toEpochSecond(LocalDateTime sourceDateTime) {
+        return TemporalAccessorUtil.toInstant(sourceDateTime).getEpochSecond();
+    }
+
 }

+ 0 - 30
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java

@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.iot.api.device;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
-import cn.iocoder.yudao.module.iot.enums.ApiConstants;
-import jakarta.validation.Valid;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-
-/**
- * 设备数据 Upstream 上行 API
- *
- * 目的:设备 -> 插件 -> 服务端
- *
- * @author haohao
- */
-public interface IotDeviceUpstreamApi {
-
-    String PREFIX = ApiConstants.PREFIX + "/device/upstream";
-
-    // TODO @芋艿:考虑 http 认证
-    /**
-     * 认证 Emqx 连接
-     *
-     * @param authReqDTO 认证 Emqx 连接 DTO
-     */
-    @PostMapping(PREFIX + "/authenticate-emqx-connection")
-    CommonResult<Boolean> authenticateEmqxConnection(@Valid @RequestBody IotDeviceEmqxAuthReqDTO authReqDTO);
-
-}

+ 0 - 4
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/package-info.java

@@ -1,4 +0,0 @@
-/**
- * TODO 芋艿:占位
- */
-package cn.iocoder.yudao.module.iot.api.device.dto;

+ 0 - 6
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java

@@ -1,6 +0,0 @@
-/**
- * 占位
- *
- * TODO 芋艿:后续删除
- */
-package cn.iocoder.yudao.module.iot.api;

+ 0 - 18
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java

@@ -39,18 +39,6 @@ public interface ErrorCodeConstants {
     ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在");
     ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除");
 
-    // ========== 插件配置 1-050-006-000 ==========
-    ErrorCode PLUGIN_CONFIG_NOT_EXISTS = new ErrorCode(1_050_006_000, "插件配置不存在");
-    ErrorCode PLUGIN_INSTALL_FAILED = new ErrorCode(1_050_006_001, "插件安装失败");
-    ErrorCode PLUGIN_INSTALL_FAILED_FILE_NAME_NOT_MATCH = new ErrorCode(1_050_006_002, "插件安装失败,文件名与原插件id不匹配");
-    ErrorCode PLUGIN_CONFIG_DELETE_FAILED_RUNNING = new ErrorCode(1_050_006_003, "请先停止插件");
-    ErrorCode PLUGIN_STATUS_INVALID = new ErrorCode(1_050_006_004, "插件状态无效");
-    ErrorCode PLUGIN_CONFIG_KEY_DUPLICATE = new ErrorCode(1_050_006_005, "插件标识已存在");
-    ErrorCode PLUGIN_START_FAILED = new ErrorCode(1_050_006_006, "插件启动失败");
-    ErrorCode PLUGIN_STOP_FAILED = new ErrorCode(1_050_006_007, "插件停止失败");
-
-    // ========== 插件实例 1-050-007-000 ==========
-
     // ========== 固件相关 1-050-008-000 ==========
 
     ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在");
@@ -66,16 +54,10 @@ public interface ErrorCodeConstants {
     ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_201, "升级记录重复");
     ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_202, "升级记录不能重试");
 
-    // ========== MQTT 通信相关 1-050-009-000 ==========
-    ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal");
-
     // ========== IoT 数据桥梁 1-050-010-000 ==========
     ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在");
 
     // ========== IoT 场景联动 1-050-011-000 ==========
     ErrorCode RULE_SCENE_NOT_EXISTS = new ErrorCode(1_050_011_000, "IoT 场景联动不存在");
 
-    // ========== IoT 产品脚本信息 1-050-012-000 ==========
-    ErrorCode PRODUCT_SCRIPT_NOT_EXISTS = new ErrorCode(1_050_012_000, "IoT 产品脚本信息不存在");
-
 }

+ 37 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.iot.api.device;
+
+import cn.iocoder.yudao.framework.common.enums.RpcConstants;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
+import jakarta.annotation.Resource;
+import jakarta.annotation.security.PermitAll;
+import org.springframework.context.annotation.Primary;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+/**
+ * IoT 设备 API 实现类
+ *
+ * @author haohao
+ */
+@RestController
+@Validated
+@Primary // 保证优先匹配,因为 yudao-iot-gateway 也有 IotDeviceCommonApi 的实现,并且也可能会被 biz 引入
+public class IoTDeviceApiImpl implements IotDeviceCommonApi {
+
+    @Resource
+    private IotDeviceService deviceService;
+
+    @Override
+    @PostMapping(RpcConstants.RPC_API_PREFIX + "/iot/device/auth")
+    @PermitAll
+    public CommonResult<Boolean> authDevice(IotDeviceAuthReqDTO authReqDTO) {
+        return success(deviceService.authDevice(authReqDTO));
+    }
+
+}

+ 0 - 30
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java

@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.iot.api.device;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
-import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
-import jakarta.annotation.Resource;
-import org.springframework.context.annotation.Primary;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.RestController;
-
-import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
-
-/**
- * * 设备数据 Upstream 上行 API 实现类
- */
-@RestController
-@Validated
-@Primary // 保证优先匹配,因为 yudao-module-iot-net-component-core 也有 IotDeviceUpstreamApi 的实现,并且也可能会被 biz 引入
-public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi {
-
-    @Resource
-    private IotDeviceUpstreamService deviceUpstreamService;
-
-    @Override
-    public CommonResult<Boolean> authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) {
-        boolean result = deviceUpstreamService.authenticateEmqxConnection(authReqDTO);
-        return success(result);
-    }
-
-}

+ 1 - 3
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java

@@ -1,6 +1,4 @@
 /**
- * 占位
- *
- * TODO 芋艿:后续删除
+ * iot API 包,定义并实现提供给其它模块的 API
  */
 package cn.iocoder.yudao.module.iot.api;

+ 1 - 14
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java

@@ -121,23 +121,10 @@ public class IotDeviceDO extends TenantBaseDO {
      */
     private String firmwareId;
 
-    // TODO @芋艿:【待定 003】:要不要增加 username?目前 tl 有,阿里云之类的没有
     /**
-     * 设备密钥,用于设备认证,需安全存储
+     * 设备密钥,用于设备认证
      */
     private String deviceSecret;
-    /**
-     * MQTT 客户端 ID
-     */
-    private String mqttClientId;
-    /**
-     * MQTT 用户名
-     */
-    private String mqttUsername;
-    /**
-     * MQTT 密码
-     */
-    private String mqttPassword;
     /**
      * 认证类型(如一机一密、动态注册)
      */

+ 12 - 11
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java

@@ -9,14 +9,15 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
  */
 public interface RedisKeyConstants {
 
+    // TODO @芋艿:弱化 deviceKey;使用 product_key + device_name 替代
     /**
      * 设备属性的数据缓存,采用 HASH 结构
      * <p>
-     * KEY 格式:device_property:{productKey},${deviceName}
+     * KEY 格式:device_property:{deviceKey}
      * HASH KEY:identifier 属性标识
      * VALUE 数据类型:String(JSON) {@link IotDevicePropertyDO}
      */
-    String DEVICE_PROPERTY = "iot:device_property:%s,%s";
+    String DEVICE_PROPERTY = "iot:device_property:%s";
 
     /**
      * 设备的最后上报时间,采用 ZSET 结构
@@ -26,6 +27,15 @@ public interface RedisKeyConstants {
      */
     String DEVICE_REPORT_TIMES = "iot:device_report_times";
 
+    /**
+     * 设备关联的网关 serverId 缓存,采用 HASH 结构
+     *
+     * KEY 格式:device_server_id
+     * HASH KEY:{productKey},{deviceName}
+     * VALUE 数据类型:String serverId
+     */
+    String DEVICE_SERVER_ID = "iot:device_server_id";
+
     /**
      * 设备信息的数据缓存,使用 Spring Cache 操作(忽略租户)
      *
@@ -42,13 +52,4 @@ public interface RedisKeyConstants {
      */
     String THING_MODEL_LIST = "iot:thing_model_list";
 
-    /**
-     * 设备关联的网关 serverId 缓存,采用 HASH 结构
-     *
-     * KEY 格式:device_server_id
-     * HASH KEY:{productKey},{deviceName}
-     * VALUE 数据类型:String serverId
-     */
-    String DEVICE_SERVER_ID = "iot:device_server_id";
-
 }

+ 0 - 29
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/config/SecurityConfiguration.java

@@ -1,29 +0,0 @@
-package cn.iocoder.yudao.module.iot.framework.security.config;
-
-import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
-import cn.iocoder.yudao.module.iot.enums.ApiConstants;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
-
-/**
- * IoT 模块的 Security 配置
- */
-@Configuration(proxyBeanMethods = false, value = "iotSecurityConfiguration")
-public class SecurityConfiguration {
-
-    @Bean("iotAuthorizeRequestsCustomizer")
-    public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
-        return new AuthorizeRequestsCustomizer() {
-
-            @Override
-            public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
-                // RPC 服务的安全配置
-                registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
-            }
-
-        };
-    }
-
-}

+ 0 - 4
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/security/core/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 占位
- */
-package cn.iocoder.yudao.module.iot.framework.security.core;

+ 9 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.service.device;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
 import jakarta.validation.Valid;
@@ -228,4 +229,12 @@ public interface IotDeviceService {
      */
     List<IotDeviceDO> getDeviceListByProductKeyAndNames(String productKey, List<String> deviceNames);
 
+    /**
+     * 认证设备
+     *
+     * @param authReqDTO 认证信息
+     * @return 是否认证成功
+     */
+    boolean authDevice(IotDeviceAuthReqDTO authReqDTO);
+
 }

+ 37 - 9
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.service.device;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.spring.SpringUtil;
@@ -12,16 +13,16 @@ import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
+import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
 import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
 import cn.iocoder.yudao.module.iot.dal.redis.RedisKeyConstants;
-import cn.iocoder.yudao.module.iot.core.enums.IotDeviceStateEnum;
 import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
-import cn.iocoder.yudao.module.iot.util.MqttSignUtils;
-import cn.iocoder.yudao.module.iot.util.MqttSignUtils.MqttSignResult;
+import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
 import jakarta.annotation.Resource;
 import jakarta.validation.ConstraintViolationException;
 import lombok.extern.slf4j.Slf4j;
@@ -397,15 +398,17 @@ public class IotDeviceServiceImpl implements IotDeviceService {
         return respVO;
     }
 
+    // TODO @芋艿:改成通用的;
     @Override
     public IotDeviceMqttConnectionParamsRespVO getMqttConnectionParams(Long deviceId) {
         IotDeviceDO device = validateDeviceExists(deviceId);
-        MqttSignResult mqttSignResult = MqttSignUtils.calculate(device.getProductKey(), device.getDeviceName(),
-                device.getDeviceSecret());
-        return new IotDeviceMqttConnectionParamsRespVO()
-                .setMqttClientId(mqttSignResult.getClientId())
-                .setMqttUsername(mqttSignResult.getUsername())
-                .setMqttPassword(mqttSignResult.getPassword());
+//        MqttSignResult mqttSignResult = MqttSignUtils.calculate(device.getProductKey(), device.getDeviceName(),
+//                device.getDeviceSecret());
+//        return new IotDeviceMqttConnectionParamsRespVO()
+//                .setMqttClientId(mqttSignResult.getClientId())
+//                .setMqttUsername(mqttSignResult.getUsername())
+//                .setMqttPassword(mqttSignResult.getPassword());
+        return null;
     }
 
     private void deleteDeviceCache(IotDeviceDO device) {
@@ -459,4 +462,29 @@ public class IotDeviceServiceImpl implements IotDeviceService {
         return deviceMapper.selectByProductKeyAndDeviceNames(productKey, deviceNames);
     }
 
+    @Override
+    public boolean authDevice(IotDeviceAuthReqDTO authReqDTO) {
+        // 1. 校验设备是否存在
+        IotDeviceAuthUtils.DeviceInfo deviceInfo = IotDeviceAuthUtils.parseUsername(authReqDTO.getUsername());
+        if (deviceInfo == null) {
+            log.error("[authDevice][认证失败,username({}) 格式不正确]", authReqDTO.getUsername());
+            return false;
+        }
+        String deviceName = deviceInfo.getDeviceName();
+        String productKey = deviceInfo.getProductKey();
+        IotDeviceDO device = getSelf().getDeviceByProductKeyAndDeviceNameFromCache(productKey, deviceName);
+        if (device == null) {
+            log.warn("[authDevice][设备({}/{}) 不存在]", productKey, deviceName);
+            return false;
+        }
+
+        // 2. 校验密码
+        IotDeviceAuthUtils.AuthInfo authInfo = IotDeviceAuthUtils.getAuthInfo(productKey, deviceName, device.getDeviceSecret());
+        if (ObjUtil.notEqual(authInfo.getPassword(), authReqDTO.getPassword())) {
+            log.error("[authDevice][设备({}/{}) 密码不正确]", productKey, deviceName);
+            return false;
+        }
+        return true;
+    }
+
 }

+ 0 - 8
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamService.java

@@ -1,6 +1,5 @@
 package cn.iocoder.yudao.module.iot.service.device.control;
 
-import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO;
 import jakarta.validation.Valid;
 
@@ -48,11 +47,4 @@ public interface IotDeviceUpstreamService {
 //     */
 //    void addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO);
 
-    /**
-     * Emqx 连接认证
-     *
-     * @param authReqDTO Emqx 连接认证 DTO
-     */
-    boolean authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO);
-
 }

+ 0 - 36
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceUpstreamServiceImpl.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.iot.service.device.control;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjUtil;
-import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
 import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO;
@@ -12,8 +11,6 @@ import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
 import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
 import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
-import cn.iocoder.yudao.module.iot.util.MqttSignUtils;
-import cn.iocoder.yudao.module.iot.util.MqttSignUtils.MqttSignResult;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -222,37 +219,4 @@ public class IotDeviceUpstreamServiceImpl implements IotDeviceUpstreamService {
 //        sendDeviceMessage(message, device);
     }
 
-    // TODO @芋艿:后续需要考虑,http 的认证
-    @Override
-    public boolean authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) {
-        log.info("[authenticateEmqxConnection][认证 Emqx 连接: {}]", authReqDTO);
-        // 1.1 校验设备是否存在。username 格式:${DeviceName}&${ProductKey}
-        String[] usernameParts = authReqDTO.getUsername().split("&");
-        if (usernameParts.length != 2) {
-            log.error("[authenticateEmqxConnection][认证失败,username 格式不正确]");
-            return false;
-        }
-        String deviceName = usernameParts[0];
-        String productKey = usernameParts[1];
-        // 1.2 获得设备
-        IotDeviceDO device = deviceService.getDeviceByProductKeyAndDeviceNameFromCache(productKey, deviceName);
-        if (device == null) {
-            log.error("[authenticateEmqxConnection][设备({}/{}) 不存在]", productKey, deviceName);
-            return false;
-        }
-        // TODO @haohao:需要记录,记录设备的最后时间
-
-        // 2. 校验密码
-        String deviceSecret = device.getDeviceSecret();
-        String clientId = authReqDTO.getClientId();
-        MqttSignResult sign = MqttSignUtils.calculate(productKey, deviceName, deviceSecret, clientId);
-        // TODO 建议,先失败,return false;
-        if (StrUtil.equals(sign.getPassword(), authReqDTO.getPassword())) {
-            log.info("[authenticateEmqxConnection][认证成功]");
-            return true;
-        }
-        log.error("[authenticateEmqxConnection][认证失败,密码不正确]");
-        return false;
-    }
-
 }

+ 0 - 69
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/util/MqttSignUtils.java

@@ -1,69 +0,0 @@
-package cn.iocoder.yudao.module.iot.util;
-
-import cn.hutool.crypto.digest.HMac;
-import cn.hutool.crypto.digest.HmacAlgorithm;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-
-import java.nio.charset.StandardCharsets;
-
-/**
- * MQTT 签名工具类
- *
- * 提供静态方法来计算 MQTT 连接参数
- */
-public class MqttSignUtils {
-
-    /**
-     * 计算 MQTT 连接参数
-     *
-     * @param productKey   产品密钥
-     * @param deviceName   设备名称
-     * @param deviceSecret 设备密钥
-     * @return 包含 clientId, username, password 的结果对象
-     */
-    public static MqttSignResult calculate(String productKey, String deviceName, String deviceSecret) {
-        return calculate(productKey, deviceName, deviceSecret, productKey + "." + deviceName);
-    }
-
-    /**
-     * 计算 MQTT 连接参数
-     *
-     * @param productKey   产品密钥
-     * @param deviceName   设备名称
-     * @param deviceSecret 设备密钥
-     * @param clientId     客户端 ID
-     * @return 包含 clientId, username, password 的结果对象
-     */
-    public static MqttSignResult calculate(String productKey, String deviceName, String deviceSecret, String clientId) {
-        String username = deviceName + "&" + productKey;
-        // 构建签名内容
-        StringBuilder signContentBuilder = new StringBuilder()
-                .append("clientId").append(clientId)
-                .append("deviceName").append(deviceName)
-                .append("deviceSecret").append(deviceSecret)
-                .append("productKey").append(productKey);
-
-        // 使用 HMac 计算签名
-        byte[] key = deviceSecret.getBytes(StandardCharsets.UTF_8);
-        String signContent = signContentBuilder.toString();
-        HMac mac = new HMac(HmacAlgorithm.HmacSHA256, key);
-        String password = mac.digestHex(signContent);
-
-        return new MqttSignResult(clientId, username, password);
-    }
-
-    /**
-     * MQTT 签名结果类
-     */
-    @Getter
-    @AllArgsConstructor
-    public static class MqttSignResult {
-
-        private final String clientId;
-        private final String username;
-        private final String password;
-
-    }
-
-}

+ 11 - 1
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/biz/IotDeviceCommonApi.java

@@ -1,5 +1,15 @@
 package cn.iocoder.yudao.module.iot.core.biz;
 
-// TODO @芋艿:待实现
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
+
+/**
+ * IoT 设备通用 API
+ *
+ * @author haohao
+ */
 public interface IotDeviceCommonApi {
+
+    CommonResult<Boolean> authDevice(IotDeviceAuthReqDTO authReqDTO);
+
 }

+ 3 - 5
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java → yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/biz/dto/IotDeviceAuthReqDTO.java

@@ -1,17 +1,15 @@
-package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
+package cn.iocoder.yudao.module.iot.core.biz.dto;
 
 import jakarta.validation.constraints.NotEmpty;
 import lombok.Data;
 
-// TODO @芋艿:要不要继承 IotDeviceUpstreamAbstractReqDTO
-// TODO @芋艿:@haohao:后续其它认证的设计
 /**
- * IoT 认证 Emqx 连接 Request DTO
+ * IoT 设备认证 Request DTO
  *
  * @author 芋道源码
  */
 @Data
-public class IotDeviceEmqxAuthReqDTO {
+public class IotDeviceAuthReqDTO {
 
     /**
      * 客户端 ID

+ 85 - 0
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceAuthUtils.java

@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.iot.core.util;
+
+import cn.hutool.crypto.digest.DigestUtil;
+import cn.hutool.crypto.digest.HmacAlgorithm;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * IoT 设备【认证】的工具类,参考阿里云
+ *
+ * @see <a href="https://help.aliyun.com/zh/iot/user-guide/how-do-i-obtain-mqtt-parameters-for-authentication">如何计算 MQTT 签名参数</a>
+ */
+public class IotDeviceAuthUtils {
+
+    /**
+     * 认证信息
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class AuthInfo {
+
+        /**
+         * 客户端 ID
+         */
+        private String clientId;
+
+        /**
+         * 用户名
+         */
+        private String username;
+
+        /**
+         * 密码
+         */
+        private String password;
+
+    }
+
+    /**
+     * 设备信息
+     */
+    @Data
+    public static class DeviceInfo {
+
+        private String productKey;
+
+        private String deviceName;
+
+    }
+
+    public static AuthInfo getAuthInfo(String productKey, String deviceName, String deviceSecret) {
+        String clientId = buildClientId(productKey, deviceName);
+        String username = buildUsername(productKey, deviceName);
+        String content = "clientId" + clientId +
+                "deviceName" + deviceName +
+                "deviceSecret" + deviceSecret +
+                "productKey" + productKey;
+        String password = buildPassword(deviceSecret, content);
+        return new AuthInfo(clientId, username, password);
+    }
+
+    private static String buildClientId(String productKey, String deviceName) {
+        return String.format("%s.%s", productKey, deviceName);
+    }
+
+    private static String buildUsername(String productKey, String deviceName) {
+        return String.format("%s&%s", deviceName, productKey);
+    }
+
+    private static String buildPassword(String deviceSecret, String content) {
+        return DigestUtil.hmac(HmacAlgorithm.HmacSHA256, deviceSecret.getBytes())
+                .digestHex(content);
+    }
+
+    public static DeviceInfo parseUsername(String username) {
+        String[] usernameParts = username.split("&");
+        if (usernameParts.length != 2) {
+            return null;
+        }
+        return new DeviceInfo().setProductKey(usernameParts[1]).setDeviceName(usernameParts[0]);
+    }
+
+}

+ 1 - 1
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java

@@ -6,7 +6,7 @@ import cn.hutool.system.SystemUtil;
 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
 
 /**
- * IoT 设备消息的工具类
+ * IoT 设备消息的工具类
  *
  * @author 芋道源码
  */

+ 5 - 0
yudao-module-iot/yudao-module-iot-gateway/pom.xml

@@ -23,6 +23,11 @@
             <version>${revision}</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+        </dependency>
+
         <!-- 消息队列相关 -->
         <dependency>
             <groupId>org.apache.rocketmq</groupId>

+ 2 - 3
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java

@@ -24,9 +24,8 @@ public class IotGatewayConfiguration {
     public static class HttpProtocolConfiguration {
 
         @Bean
-        public IotHttpUpstreamProtocol iotHttpUpstreamProtocol(IotGatewayProperties gatewayProperties,
-                                                               IotDeviceMessageProducer deviceMessageProducer) {
-            return new IotHttpUpstreamProtocol(gatewayProperties.getProtocol().getHttp(), deviceMessageProducer);
+        public IotHttpUpstreamProtocol iotHttpUpstreamProtocol(IotGatewayProperties gatewayProperties) {
+            return new IotHttpUpstreamProtocol(gatewayProperties.getProtocol().getHttp());
         }
 
         @Bean

+ 30 - 2
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java

@@ -1,9 +1,12 @@
 package cn.iocoder.yudao.module.iot.gateway.config;
 
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.validation.annotation.Validated;
 
+import java.time.Duration;
 import java.util.List;
 
 @ConfigurationProperties(prefix = "yudao.iot.gateway")
@@ -15,6 +18,10 @@ public class IotGatewayProperties {
      * 设备 RPC 服务配置
      */
     private RpcProperties rpc;
+    /**
+     * Token 配置
+     */
+    private TokenProperties token;
 
     /**
      * 协议配置
@@ -27,15 +34,34 @@ public class IotGatewayProperties {
         /**
          * 主程序 API 地址
          */
+        @NotEmpty(message = "主程序 API 地址不能为空")
         private String url;
         /**
          * 连接超时时间
          */
-        private String connectTimeout;
+        @NotNull(message = "连接超时时间不能为空")
+        private Duration connectTimeout;
         /**
          * 读取超时时间
          */
-        private String readTimeout;
+        @NotNull(message = "读取超时时间不能为空")
+        private Duration readTimeout;
+
+    }
+
+    @Data
+    public static class TokenProperties {
+
+        /**
+         * 密钥
+         */
+        @NotEmpty(message = "密钥不能为空")
+        private String secret;
+        /**
+         * 令牌有效期
+         */
+        @NotNull(message = "令牌有效期不能为空")
+        private Duration expiration;
 
     }
 
@@ -60,6 +86,7 @@ public class IotGatewayProperties {
         /**
          * 是否开启
          */
+        @NotNull(message = "是否开启不能为空")
         private Boolean enabled;
         /**
          * 服务端口
@@ -74,6 +101,7 @@ public class IotGatewayProperties {
         /**
          * 是否开启
          */
+        @NotNull(message = "是否开启不能为空")
         private Boolean enabled;
         /**
          * MQTT 服务器地址

+ 16 - 0
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/enums/ErrorCodeConstants.java

@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.iot.gateway.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+/**
+ * iot gateway 错误码枚举类
+ * <p>
+ * iot 系统,使用 1-051-000-000 段
+ */
+public interface ErrorCodeConstants {
+
+    // ========== 设备认证 1-050-001-000 ============
+    ErrorCode DEVICE_AUTH_FAIL = new ErrorCode(1_051_001_000, "设备鉴权失败"); // 对应阿里云 20000
+    ErrorCode DEVICE_TOKEN_EXPIRED = new ErrorCode(1_051_001_002, "token 失效。需重新调用 auth 进行鉴权,获取token"); // 对应阿里云 20001
+
+}

+ 4 - 5
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpUpstreamProtocol.java

@@ -1,8 +1,8 @@
 package cn.iocoder.yudao.module.iot.gateway.protocol.http;
 
-import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
 import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
 import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties;
+import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpAuthHandler;
 import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpUpstreamHandler;
 import io.vertx.core.AbstractVerticle;
 import io.vertx.core.Vertx;
@@ -25,8 +25,6 @@ public class IotHttpUpstreamProtocol extends AbstractVerticle {
 
     private final IotGatewayProperties.HttpProperties httpProperties;
 
-    private final IotDeviceMessageProducer deviceMessageProducer;
-
     private HttpServer httpServer;
 
     @Override
@@ -38,10 +36,11 @@ public class IotHttpUpstreamProtocol extends AbstractVerticle {
         router.route().handler(BodyHandler.create());
 
         // 创建处理器,添加路由处理器
-        IotHttpUpstreamHandler upstreamHandler = new IotHttpUpstreamHandler(
-                this, deviceMessageProducer);
+        IotHttpUpstreamHandler upstreamHandler = new IotHttpUpstreamHandler(this);
         router.post(IotHttpUpstreamHandler.PROPERTY_PATH).handler(upstreamHandler);
         router.post(IotHttpUpstreamHandler.EVENT_PATH).handler(upstreamHandler);
+        IotHttpAuthHandler authHandler = new IotHttpAuthHandler(this);
+        router.post(IotHttpAuthHandler.PATH).handler(authHandler);
 
         // 启动 HTTP 服务器
         try {

+ 98 - 0
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAbstractHandler.java

@@ -0,0 +1,98 @@
+package cn.iocoder.yudao.module.iot.gateway.protocol.http.router;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
+import cn.iocoder.yudao.module.iot.gateway.service.auth.IotDeviceTokenService;
+import io.vertx.core.Handler;
+import io.vertx.core.http.HttpHeaders;
+import io.vertx.ext.web.RoutingContext;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.MediaType;
+
+import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.FORBIDDEN;
+import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
+
+/**
+ * IoT 网关 HTTP 协议的处理器抽象基类:提供通用的前置处理(认证)、全局的异常捕获等
+ *
+ * @author 芋道源码
+ */
+@RequiredArgsConstructor
+@Slf4j
+public abstract class IotHttpAbstractHandler implements Handler<RoutingContext> {
+
+    private final IotDeviceTokenService deviceTokenService = SpringUtil.getBean(IotDeviceTokenService.class);
+
+    @Override
+    public void handle(RoutingContext context) {
+        try {
+            // 1. 前置处理
+            CommonResult<Object> result = beforeHandle(context);
+            if (result != null) {
+                writeResponse(context, result);
+                return;
+            }
+
+            // 2. 执行逻辑
+            result = handle0(context);
+            writeResponse(context, result);
+        } catch (ServiceException e) {
+            writeResponse(context, CommonResult.error(e.getCode(), e.getMessage()));
+        } catch (Exception e) {
+            log.error("[handle][path({}) 处理异常]", context.request().path(), e);
+            writeResponse(context, CommonResult.error(INTERNAL_SERVER_ERROR));
+        }
+    }
+
+    protected abstract CommonResult<Object> handle0(RoutingContext context);
+
+    private CommonResult<Object> beforeHandle(RoutingContext context) {
+        // 如果不需要认证,则不走前置处理
+        String path = context.request().path();
+        if (ObjUtil.equal(path, IotHttpAuthHandler.PATH)) {
+            return null;
+        }
+
+        // 解析参数
+        String token = context.request().getHeader(HttpHeaders.AUTHORIZATION);
+        if (StrUtil.isEmpty(token)) {
+            throw invalidParamException("token 不能为空");
+        }
+        String productKey = context.pathParam("productKey");
+        if (StrUtil.isEmpty(productKey)) {
+            throw invalidParamException("productKey 不能为空");
+        }
+        String deviceName = context.pathParam("deviceName");
+        if (StrUtil.isEmpty(deviceName)) {
+            throw invalidParamException("deviceName 不能为空");
+        }
+
+        // 校验 token
+        IotDeviceAuthUtils.DeviceInfo deviceInfo = deviceTokenService.verifyToken(token);
+        Assert.notNull(deviceInfo, "设备信息不能为空");
+        // 校验设备信息是否匹配
+        if (ObjUtil.notEqual(productKey, deviceInfo.getProductKey())
+                || ObjUtil.notEqual(deviceName, deviceInfo.getDeviceName())) {
+            throw exception(FORBIDDEN);
+        }
+        return null;
+    }
+
+    @SuppressWarnings("deprecation")
+    public static void writeResponse(RoutingContext context, Object data) {
+        context.response()
+                .setStatusCode(200)
+                .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
+                .end(JsonUtils.toJsonString(data));
+    }
+
+}

+ 84 - 0
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAuthHandler.java

@@ -0,0 +1,84 @@
+package cn.iocoder.yudao.module.iot.gateway.protocol.http.router;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
+import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
+import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
+import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol;
+import cn.iocoder.yudao.module.iot.gateway.service.auth.IotDeviceTokenService;
+import io.vertx.core.json.JsonObject;
+import io.vertx.ext.web.RoutingContext;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.module.iot.gateway.enums.ErrorCodeConstants.DEVICE_AUTH_FAIL;
+
+/**
+ * IoT 网关 HTTP 协议的【认证】处理器
+ *
+ * 参考 <a href="阿里云 IoT —— HTTPS 连接通信">https://help.aliyun.com/zh/iot/user-guide/establish-connections-over-https</a>
+ *
+ * @author 芋道源码
+ */
+public class IotHttpAuthHandler extends IotHttpAbstractHandler {
+
+    public static final String PATH = "/auth";
+
+    private final IotHttpUpstreamProtocol protocol;
+
+    private final IotDeviceMessageProducer deviceMessageProducer;
+
+    private final IotDeviceTokenService deviceTokenService;
+
+    private final IotDeviceCommonApi deviceClientService;
+
+    public IotHttpAuthHandler(IotHttpUpstreamProtocol protocol) {
+        this.protocol = protocol;
+        this.deviceMessageProducer = SpringUtil.getBean(IotDeviceMessageProducer.class);
+        this.deviceTokenService = SpringUtil.getBean(IotDeviceTokenService.class);
+        this.deviceClientService = SpringUtil.getBean(IotDeviceCommonApi.class);
+    }
+
+    @Override
+    public CommonResult<Object> handle0(RoutingContext context) {
+        // 解析参数
+        JsonObject body = context.body().asJsonObject();
+        String clientId = body.getString("clientId");
+        if (StrUtil.isEmpty(clientId)) {
+            throw invalidParamException("clientId 不能为空");
+        }
+        String username = body.getString("username");
+        if (StrUtil.isEmpty(username)) {
+            throw invalidParamException("username 不能为空");
+        }
+        String password = body.getString("password");
+        if (StrUtil.isEmpty(password)) {
+            throw invalidParamException("password 不能为空");
+        }
+
+        // 执行认证
+        CommonResult<Boolean> result = deviceClientService.authDevice(new IotDeviceAuthReqDTO()
+                .setClientId(clientId).setUsername(username).setPassword(password));
+        if (result == null || !result.isSuccess()) {
+            throw exception(DEVICE_AUTH_FAIL);
+        }
+
+        // 生成 Token
+        IotDeviceAuthUtils.DeviceInfo deviceInfo = deviceTokenService.parseUsername(username);
+        Assert.notNull(deviceInfo, "设备信息不能为空");
+        String token = deviceTokenService.createToken(deviceInfo.getProductKey(), deviceInfo.getDeviceName());
+        Assert.notBlank(token, "生成 token 不能为空位");
+
+        // TODO @芋艿:发送上线消息;
+
+        // 构建响应数据
+        return success(MapUtil.of("token", token));
+    }
+
+}

+ 26 - 55
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.gateway.protocol.http.router;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
 import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
@@ -16,11 +17,8 @@ import lombok.extern.slf4j.Slf4j;
 
 import java.util.Map;
 
-import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
-import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
-
 /**
- * IoT 网关 HTTP 协议的处理器
+ * IoT 网关 HTTP 协议的【上行】处理器
  *
  * @author 芋道源码
  */
@@ -54,47 +52,35 @@ public class IotHttpUpstreamHandler implements Handler<RoutingContext> {
     private static final String EVENT_METHOD_SUFFIX = ".post";
 
     private final IotHttpUpstreamProtocol protocol;
-//    /**
-//     * 设备上行 API
-//     */
-//    private final IotDeviceUpstreamApi deviceUpstreamApi;
-    /**
-     * 设备消息生产者
-     */
-    private final IotDeviceMessageProducer deviceMessageProducer;
 
-    @Override
-    public void handle(RoutingContext routingContext) {
-        String path = routingContext.request().path();
+    private final IotDeviceMessageProducer deviceMessageProducer;
 
-        try {
-            // 1. 解析通用参数
-            Map<String, String> params = parseCommonParams(routingContext);
-            String productKey = params.get("productKey");
-            String deviceName = params.get("deviceName");
-            JsonObject body = routingContext.body().asJsonObject();
+    public IotHttpUpstreamHandler(IotHttpUpstreamProtocol protocol) {
+        this.protocol = protocol;
+        this.deviceMessageProducer = SpringUtil.getBean(IotDeviceMessageProducer.class);
+    }
 
-            // 2. 根据路径模式处理不同类型的请求
-            if (isPropertyPostPath(path)) {
-                // 处理属性上报
-                handlePropertyPost(routingContext, productKey, deviceName, body);
-                return;
-            }
+    @Override
+    public void handle(RoutingContext context) {
+        String path = context.request().path();
+        // 1. 解析通用参数
+        Map<String, String> params = parseCommonParams(context);
+        String productKey = params.get("productKey");
+        String deviceName = params.get("deviceName");
+        JsonObject body = context.body().asJsonObject();
 
-            if (isEventPostPath(path)) {
-                // 处理事件上报
-                String identifier = routingContext.pathParam("identifier");
-                handleEventPost(routingContext, productKey, deviceName, identifier, body);
-                return;
-            }
+        // 2. 根据路径模式处理不同类型的请求
+        if (isPropertyPostPath(path)) {
+            // 处理属性上报
+            handlePropertyPost(context, productKey, deviceName, body);
+            return;
+        }
 
-            // 不支持的请求路径
-            sendErrorResponse(routingContext,  "unknown", BAD_REQUEST.getCode(), "不支持的请求路径");
-        } catch (Exception e) {
-            log.error("[handle][处理上行请求异常] path={}", path, e);
-            String method = determineMethodFromPath(path, routingContext);
-            sendErrorResponse(routingContext, method, INTERNAL_SERVER_ERROR.getCode(),
-                    INTERNAL_SERVER_ERROR.getMsg());
+        if (isEventPostPath(path)) {
+            // 处理事件上报
+            String identifier = context.pathParam("identifier");
+            handleEventPost(context, productKey, deviceName, identifier, body);
+            return;
         }
     }
 
@@ -169,7 +155,6 @@ public class IotHttpUpstreamHandler implements Handler<RoutingContext> {
 //
 //        // 事件上报
 //        CommonResult<Boolean> result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO);
-//        String method = EVENT_METHOD_PREFIX + identifier + EVENT_METHOD_SUFFIX;
 //
 //        // 返回响应
 //        sendResponse(routingContext, requestId, method, result);
@@ -195,20 +180,6 @@ public class IotHttpUpstreamHandler implements Handler<RoutingContext> {
 //        IotNetComponentCommonUtils.writeJsonResponse(routingContext, response);
     }
 
-    /**
-     * 发送错误响应
-     *
-     * @param routingContext 路由上下文
-     * @param method         方法名
-     * @param code           错误代码
-     * @param message        错误消息
-     */
-    private void sendErrorResponse(RoutingContext routingContext, String method, Integer code,
-                                   String message) {
-//        IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, code, message);
-//        IotNetComponentCommonUtils.writeJsonResponse(routingContext, errorResponse);
-    }
-
     /**
      * 从路径确定方法名
      *

+ 37 - 0
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/auth/IotDeviceTokenService.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.iot.gateway.service.auth;
+
+import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
+
+/**
+ * IoT 设备 Token 服务 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface IotDeviceTokenService {
+
+    /**
+     * 创建设备 Token
+     *
+     * @param productKey 产品 Key
+     * @param deviceName 设备名称
+     * @return 设备 Token
+     */
+    String createToken(String productKey, String deviceName);
+
+    /**
+     * 验证设备 Token
+     *
+     * @param token 设备 Token
+     * @return 设备信息
+     */
+    IotDeviceAuthUtils.DeviceInfo verifyToken(String token);
+
+    /**
+     * 解析用户名
+     *
+     * @param username 用户名
+     * @return 设备信息
+     */
+    IotDeviceAuthUtils.DeviceInfo parseUsername(String username);
+
+}

+ 79 - 0
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/auth/IotDeviceTokenServiceImpl.java

@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.module.iot.gateway.service.auth;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.json.JSONObject;
+import cn.hutool.jwt.JWT;
+import cn.hutool.jwt.JWTUtil;
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
+import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
+import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.iot.gateway.enums.ErrorCodeConstants.DEVICE_TOKEN_EXPIRED;
+
+/**
+ * IoT 设备 Token Service 实现类:调用远程的 device http 接口,进行设备 Token 生成、解析等逻辑
+ *
+ * 注意:目前仅 HTTP 协议使用
+ *
+ * @author 芋道源码
+ */
+@Service
+@Slf4j
+public class IotDeviceTokenServiceImpl implements IotDeviceTokenService {
+
+    @Resource
+    private IotGatewayProperties gatewayProperties;
+
+    @Override
+    public String createToken(String productKey, String deviceName) {
+        Assert.notBlank(productKey, "productKey 不能为空");
+        Assert.notBlank(deviceName, "deviceName 不能为空");
+        // 构建 JWT payload
+        Map<String, Object> payload = new HashMap<>();
+        payload.put("productKey", productKey);
+        payload.put("deviceName", deviceName);
+        LocalDateTime expireTime = LocalDateTimeUtils.addTime(gatewayProperties.getToken().getExpiration());
+        payload.put("exp", LocalDateTimeUtils.toEpochSecond(expireTime)); // 过期时间(exp 是 JWT 规范推荐)
+
+        // 生成 JWT Token
+        return JWTUtil.createToken(payload, gatewayProperties.getToken().getSecret().getBytes());
+    }
+
+    @Override
+    public IotDeviceAuthUtils.DeviceInfo verifyToken(String token) {
+        Assert.notBlank(token, "token 不能为空");
+        // 校验 JWT Token
+        boolean verify = JWTUtil.verify(token, gatewayProperties.getToken().getSecret().getBytes());
+        if (!verify) {
+            throw exception(DEVICE_TOKEN_EXPIRED);
+        }
+
+        // 解析 Token
+        JWT jwt = JWTUtil.parseToken(token);
+        JSONObject payload = jwt.getPayloads();
+        // 检查过期时间
+        Long exp = payload.getLong("exp");
+        if (exp == null || exp > System.currentTimeMillis() / 1000) {
+            throw exception(DEVICE_TOKEN_EXPIRED);
+        }
+        String productKey = payload.getStr("productKey");
+        String deviceName = payload.getStr("deviceName");
+        Assert.notBlank(productKey, "productKey 不能为空");
+        Assert.notBlank(deviceName, "deviceName 不能为空");
+        return new IotDeviceAuthUtils.DeviceInfo().setProductKey(productKey).setDeviceName(deviceName);
+    }
+
+    @Override
+    public IotDeviceAuthUtils.DeviceInfo parseUsername(String username) {
+        return IotDeviceAuthUtils.parseUsername(username);
+    }
+
+}

+ 58 - 0
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/device/IotDeviceClientServiceImpl.java

@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.iot.gateway.service.device;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
+import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
+
+/**
+ * Iot 设备信息 Service 实现类:调用远程的 device http 接口,进行设备认证、设备获取等
+ *
+ * @author 芋道源码
+ */
+@Service
+@Slf4j
+public class IotDeviceClientServiceImpl implements IotDeviceCommonApi {
+
+    @Resource
+    private IotGatewayProperties gatewayProperties;
+
+    private RestTemplate restTemplate;
+
+    @PostConstruct
+    public void init() {
+        IotGatewayProperties.RpcProperties rpc = gatewayProperties.getRpc();
+        restTemplate = new RestTemplateBuilder()
+                .rootUri(rpc.getUrl() + "/rpc-api/iot/device/")
+                .readTimeout(rpc.getReadTimeout())
+                .connectTimeout(rpc.getConnectTimeout())
+                .build();
+    }
+
+    @Override
+    public CommonResult<Boolean> authDevice(IotDeviceAuthReqDTO authReqDTO) {
+        return doPost("auth", authReqDTO);
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T> CommonResult<Boolean> doPost(String url, T requestBody) {
+        try {
+            CommonResult<Boolean> result = restTemplate.postForObject(url, requestBody,
+                    (Class<CommonResult<Boolean>>) (Class<?>) CommonResult.class);
+            log.info("[doPost][url({}) requestBody({}) result({})]", url, requestBody, result);
+            return result;
+        } catch (Exception e) {
+            log.error("[doPost][url({}) requestBody({}) 发生异常]", url, requestBody, e);
+            return CommonResult.error(INTERNAL_SERVER_ERROR);
+        }
+    }
+
+}

+ 4 - 0
yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml

@@ -22,6 +22,10 @@ yudao:
         url: http://127.0.0.1:48080 # 主程序 API 地址
         connect-timeout: 30s
         read-timeout: 30s
+      # 设备 Token 配置
+      token:
+        secret: 1234567890123456789012345678901
+        expiration: 7d
 
       # 协议配置
       protocol:

+ 139 - 0
yudao-module-iot/yudao-module-iot-gateway/src/test/java/cn/iocoder/yudao/module/iot/gateway/service/auth/IotDeviceTokenServiceImplTest.java

@@ -0,0 +1,139 @@
+package cn.iocoder.yudao.module.iot.gateway.service.auth;
+
+import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
+import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.time.Duration;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.when;
+
+/**
+ * {@link IotDeviceTokenServiceImpl} 的单元测试
+ *
+ * @author 芋道源码
+ */
+@ExtendWith(MockitoExtension.class)
+class IotDeviceTokenServiceImplTest {
+
+    @Mock
+    private IotGatewayProperties gatewayProperties;
+
+    @InjectMocks
+    private IotDeviceTokenServiceImpl tokenService;
+
+    private IotGatewayProperties.TokenProperties tokenProperties;
+
+    @BeforeEach
+    void setUp() {
+        // 初始化 Token 配置
+        tokenProperties = new IotGatewayProperties.TokenProperties();
+        tokenProperties.setSecret("1234567890123456789012345678901");
+        tokenProperties.setExpiration(Duration.ofDays(7));
+        
+        when(gatewayProperties.getToken()).thenReturn(tokenProperties);
+    }
+
+    @Test
+    void testCreateToken_Success() {
+        // 准备参数
+        String productKey = "testProduct";
+        String deviceName = "testDevice";
+
+        // 调用方法
+        String token = tokenService.createToken(productKey, deviceName);
+
+        // 验证结果
+        assertNotNull(token);
+        assertFalse(token.isEmpty());
+    }
+
+    @Test
+    void testCreateToken_WithBlankParameters() {
+        // 测试空白参数
+        assertNull(tokenService.createToken("", "deviceName"));
+        assertNull(tokenService.createToken("productKey", ""));
+        assertNull(tokenService.createToken(null, "deviceName"));
+        assertNull(tokenService.createToken("productKey", null));
+    }
+
+    @Test
+    void testCreateToken_WithoutConfig() {
+        // 模拟配置为空
+        when(gatewayProperties.getToken()).thenReturn(null);
+
+        // 调用方法
+        String token = tokenService.createToken("productKey", "deviceName");
+
+        // 验证结果
+        assertNull(token);
+    }
+
+    @Test
+    void testVerifyToken_Success() {
+        // 准备参数
+        String productKey = "testProduct";
+        String deviceName = "testDevice";
+
+        // 创建 Token
+        String token = tokenService.createToken(productKey, deviceName);
+        assertNotNull(token);
+
+        // 验证 Token
+        IotDeviceAuthUtils.DeviceInfo deviceInfo = tokenService.verifyToken(token);
+
+        // 验证结果
+        assertNotNull(deviceInfo);
+        assertEquals(productKey, deviceInfo.getProductKey());
+        assertEquals(deviceName, deviceInfo.getDeviceName());
+    }
+
+    @Test
+    void testVerifyToken_WithBlankToken() {
+        // 测试空白 Token
+        assertNull(tokenService.verifyToken(""));
+        assertNull(tokenService.verifyToken(null));
+    }
+
+    @Test
+    void testVerifyToken_WithInvalidToken() {
+        // 测试无效 Token
+        assertNull(tokenService.verifyToken("invalid.token.here"));
+    }
+
+    @Test
+    void testVerifyToken_WithoutConfig() {
+        // 模拟配置为空
+        when(gatewayProperties.getToken()).thenReturn(null);
+
+        // 调用方法
+        IotDeviceAuthUtils.DeviceInfo deviceInfo = tokenService.verifyToken("any.token.here");
+
+        // 验证结果
+        assertNull(deviceInfo);
+    }
+
+    @Test
+    void testTokenRoundTrip() {
+        // 测试完整的 Token 创建和验证流程
+        String productKey = "myProduct";
+        String deviceName = "myDevice";
+
+        // 1. 创建 Token
+        String token = tokenService.createToken(productKey, deviceName);
+        assertNotNull(token);
+
+        // 2. 验证 Token
+        IotDeviceAuthUtils.DeviceInfo deviceInfo = tokenService.verifyToken(token);
+        assertNotNull(deviceInfo);
+        assertEquals(productKey, deviceInfo.getProductKey());
+        assertEquals(deviceName, deviceInfo.getDeviceName());
+    }
+
+} 

+ 0 - 25
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonAutoConfiguration.java

@@ -1,25 +0,0 @@
-package cn.iocoder.yudao.module.iot.net.component.core.config;
-
-import cn.iocoder.yudao.module.iot.net.component.core.upstream.IotDeviceUpstreamClient;
-import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.scheduling.annotation.EnableScheduling;
-
-/**
- * IoT 网络组件的通用自动配置类
- *
- * @author haohao
- */
-@EnableConfigurationProperties(IotNetComponentCommonProperties.class)
-public class IotNetComponentCommonAutoConfiguration {
-
-    /**
-     * 创建设备上行客户端
-     */
-    @Bean
-    public IotDeviceUpstreamClient deviceUpstreamClient() {
-        return new IotDeviceUpstreamClient();
-    }
-
-}

+ 0 - 26
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/upstream/IotDeviceUpstreamClient.java

@@ -1,26 +0,0 @@
-package cn.iocoder.yudao.module.iot.net.component.core.upstream;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
-import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-/**
- * 设备数据 Upstream 上行客户端
- * <p>
- * 直接调用 IotDeviceUpstreamApi 接口
- *
- * @author haohao
- */
-@Slf4j
-public class IotDeviceUpstreamClient implements IotDeviceUpstreamApi {
-
-    @Resource
-    private IotDeviceUpstreamApi deviceUpstreamApi;
-
-    @Override
-    public CommonResult<Boolean> authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) {
-        return deviceUpstreamApi.authenticateEmqxConnection(authReqDTO);
-    }
-
-}

+ 0 - 56
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/util/IotNetComponentCommonUtils.java

@@ -1,56 +0,0 @@
-package cn.iocoder.yudao.module.iot.net.component.core.util;
-
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
-import cn.iocoder.yudao.module.iot.net.component.core.pojo.IotStandardResponse;
-import io.vertx.core.http.HttpHeaders;
-import io.vertx.ext.web.RoutingContext;
-import org.springframework.http.MediaType;
-
-/**
- * IoT 网络组件的通用工具类
- *
- * @author 芋道源码
- */
-public class IotNetComponentCommonUtils {
-
-    /**
-     * 将对象转换为JSON字符串后写入HTTP响应
-     *
-     * @param routingContext 路由上下文
-     * @param data           数据对象
-     */
-    @SuppressWarnings("deprecation")
-    public static void writeJsonResponse(RoutingContext routingContext, Object data) {
-        routingContext.response()
-                .setStatusCode(200)
-                .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
-                .end(JsonUtils.toJsonString(data));
-    }
-
-    /**
-     * 生成标准JSON格式的响应并写入HTTP响应(基于IotStandardResponse)
-     * <p>
-     * 推荐使用此方法,统一 MQTT 和 HTTP 的响应格式。使用方式:
-     *
-     * <pre>
-     * // 成功响应
-     * IotStandardResponse response = IotStandardResponse.success(requestId, method, data);
-     * IotNetComponentCommonUtils.writeJsonResponse(routingContext, response);
-     *
-     * // 错误响应
-     * IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, code, message);
-     * IotNetComponentCommonUtils.writeJsonResponse(routingContext, errorResponse);
-     * </pre>
-     *
-     * @param routingContext 路由上下文
-     * @param response       IotStandardResponse 响应对象
-     */
-    @SuppressWarnings("deprecation")
-    public static void writeJsonResponse(RoutingContext routingContext, IotStandardResponse response) {
-        routingContext.response()
-                .setStatusCode(200)
-                .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
-                .end(JsonUtils.toJsonString(response));
-    }
-
-}

+ 0 - 1
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -1 +0,0 @@
-cn.iocoder.yudao.module.iot.net.component.core.config.IotNetComponentCommonAutoConfiguration

+ 1 - 1
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-emqx/src/main/java/cn/iocoder/yudao/module/iot/net/component/emqx/upstream/router/IotDeviceAuthVertxHandler.java

@@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.net.component.emqx.upstream.router;
 
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
-import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEmqxAuthReqDTO;
+import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceEmqxAuthReqDTO;
 import cn.iocoder.yudao.module.iot.net.component.core.util.IotNetComponentCommonUtils;
 import io.vertx.core.Handler;
 import io.vertx.core.json.JsonObject;

+ 0 - 46
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/upstream/IotComponentUpstreamClient.java

@@ -1,46 +0,0 @@
-package cn.iocoder.yudao.module.iot.net.component.server.upstream;
-
-import cn.iocoder.yudao.framework.common.pojo.CommonResult;
-import cn.iocoder.yudao.module.iot.net.component.server.config.IotNetComponentServerProperties;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.client.RestTemplate;
-
-import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
-
-/**
- * 组件上行客户端,用于向主程序上报设备数据
- * <p>
- * 通过 HTTP 调用远程的 IotDeviceUpstreamApi 接口
- *
- * @author haohao
- */
-@RequiredArgsConstructor
-@Slf4j
-public class IotComponentUpstreamClient {
-
-    public static final String URL_PREFIX = "/rpc-api/iot/device/upstream";
-
-    private final IotNetComponentServerProperties properties;
-
-    private final RestTemplate restTemplate;
-
-//    @Override
-//    public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
-//        String url = properties.getUpstreamUrl() + URL_PREFIX + "/update-state";
-//        return doPost(url, updateReqDTO);
-//    }
-
-    @SuppressWarnings("unchecked")
-    private <T> CommonResult<Boolean> doPost(String url, T requestBody) {
-        try {
-            CommonResult<Boolean> result = restTemplate.postForObject(url, requestBody,
-                    (Class<CommonResult<Boolean>>) (Class<?>) CommonResult.class);
-            log.info("[doPost][url({}) requestBody({}) result({})]", url, requestBody, result);
-            return result;
-        } catch (Exception e) {
-            log.error("[doPost][url({}) requestBody({}) 发生异常]", url, requestBody, e);
-            return CommonResult.error(INTERNAL_SERVER_ERROR);
-        }
-    }
-}