Commit 21472e8dfad464b41dea9bd7b1479c7877e488c9
1 parent
c3499af5
feat:【IoT 物联网】新增 MQTT HTTP 认证协议,优化设备认证逻辑,更新配置文件以支持 HTTP 认证服务
Showing
13 changed files
with
487 additions
and
200 deletions
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java
| ... | ... | @@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.iot.gateway.config; |
| 3 | 3 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; |
| 4 | 4 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpDownstreamSubscriber; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol; |
| 6 | +import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttDownstreamSubscriber; | |
| 7 | +import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttHttpAuthProtocol; | |
| 8 | +import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttUpstreamProtocol; | |
| 6 | 9 | import lombok.extern.slf4j.Slf4j; |
| 7 | 10 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| 8 | 11 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| ... | ... | @@ -42,17 +45,24 @@ public class IotGatewayConfiguration { |
| 42 | 45 | @Slf4j |
| 43 | 46 | public static class MqttProtocolConfiguration { |
| 44 | 47 | |
| 45 | - // TODO @haohao:临时注释,避免报错 | |
| 46 | -// @Bean | |
| 47 | -// public IotMqttUpstreamProtocol iotMqttUpstreamProtocol(IotGatewayProperties gatewayProperties) { | |
| 48 | -// return new IotMqttUpstreamProtocol(gatewayProperties.getProtocol().getEmqx()); | |
| 49 | -// } | |
| 50 | -// | |
| 51 | -// @Bean | |
| 52 | -// public IotMqttDownstreamSubscriber iotMqttDownstreamSubscriber(IotMqttUpstreamProtocol mqttUpstreamProtocol, | |
| 53 | -// IotMessageBus messageBus) { | |
| 54 | -// return new IotMqttDownstreamSubscriber(mqttUpstreamProtocol, messageBus); | |
| 55 | -// } | |
| 48 | + @Bean | |
| 49 | + public IotMqttUpstreamProtocol iotMqttUpstreamProtocol(IotGatewayProperties gatewayProperties) { | |
| 50 | + return new IotMqttUpstreamProtocol(gatewayProperties.getProtocol().getEmqx()); | |
| 51 | + } | |
| 52 | + | |
| 53 | + @Bean | |
| 54 | + public IotMqttDownstreamSubscriber iotMqttDownstreamSubscriber(IotMqttUpstreamProtocol mqttUpstreamProtocol, | |
| 55 | + IotMessageBus messageBus) { | |
| 56 | + return new IotMqttDownstreamSubscriber(mqttUpstreamProtocol, messageBus); | |
| 57 | + } | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * MQTT HTTP 认证协议:提供 HTTP 认证接口供 EMQX 调用 | |
| 61 | + */ | |
| 62 | + @Bean | |
| 63 | + public IotMqttHttpAuthProtocol mqttHttpAuthProtocol(IotGatewayProperties gatewayProperties) { | |
| 64 | + return new IotMqttHttpAuthProtocol(gatewayProperties.getProtocol().getEmqx()); | |
| 65 | + } | |
| 56 | 66 | } |
| 57 | 67 | |
| 58 | 68 | } | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java
| ... | ... | @@ -104,6 +104,10 @@ public class IotGatewayProperties { |
| 104 | 104 | @NotNull(message = "是否开启不能为空") |
| 105 | 105 | private Boolean enabled; |
| 106 | 106 | /** |
| 107 | + * HTTP 认证端口 | |
| 108 | + */ | |
| 109 | + private Integer httpAuthPort = 8090; | |
| 110 | + /** | |
| 107 | 111 | * MQTT 服务器地址 |
| 108 | 112 | */ |
| 109 | 113 | private String mqttHost; |
| ... | ... | @@ -127,10 +131,6 @@ public class IotGatewayProperties { |
| 127 | 131 | * MQTT 主题 |
| 128 | 132 | */ |
| 129 | 133 | private List<String> mqttTopics; |
| 130 | - /** | |
| 131 | - * 认证端口 | |
| 132 | - */ | |
| 133 | - private Integer authPort; | |
| 134 | 134 | |
| 135 | 135 | } |
| 136 | 136 | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/IotMqttDownstreamSubscriber.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.gateway.protocol.mqtt; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.json.JSONObject; |
| 4 | +import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; | |
| 5 | +import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceGetReqDTO; | |
| 6 | +import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceRespDTO; | |
| 4 | 7 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; |
| 5 | 8 | import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; |
| 6 | 9 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 7 | 10 | import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; |
| 8 | 11 | import cn.iocoder.yudao.module.iot.gateway.enums.IotDeviceTopicEnum; |
| 9 | -import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceCacheService; | |
| 10 | 12 | import jakarta.annotation.PostConstruct; |
| 11 | 13 | import jakarta.annotation.Resource; |
| 12 | 14 | import lombok.RequiredArgsConstructor; |
| ... | ... | @@ -25,7 +27,7 @@ public class IotMqttDownstreamSubscriber implements IotMessageSubscriber<IotDevi |
| 25 | 27 | private final IotMessageBus messageBus; |
| 26 | 28 | |
| 27 | 29 | @Resource |
| 28 | - private IotDeviceCacheService deviceCacheService; | |
| 30 | + private IotDeviceCommonApi deviceApi; | |
| 29 | 31 | |
| 30 | 32 | @PostConstruct |
| 31 | 33 | public void init() { |
| ... | ... | @@ -81,7 +83,9 @@ public class IotMqttDownstreamSubscriber implements IotMessageSubscriber<IotDevi |
| 81 | 83 | String method = message.getMethod(); |
| 82 | 84 | |
| 83 | 85 | // 通过 deviceId 获取设备信息 |
| 84 | - IotDeviceCacheService.DeviceInfo deviceInfo = deviceCacheService.getDeviceInfoById(message.getDeviceId()); | |
| 86 | + IotDeviceGetReqDTO reqDTO = new IotDeviceGetReqDTO(); | |
| 87 | + reqDTO.setId(message.getDeviceId()); | |
| 88 | + IotDeviceRespDTO deviceInfo = deviceApi.getDevice(reqDTO).getData(); | |
| 85 | 89 | if (deviceInfo == null) { |
| 86 | 90 | log.warn("[handlePropertyMessage][设备信息不存在][deviceId: {}]", message.getDeviceId()); |
| 87 | 91 | return; |
| ... | ... | @@ -116,7 +120,9 @@ public class IotMqttDownstreamSubscriber implements IotMessageSubscriber<IotDevi |
| 116 | 120 | String method = message.getMethod(); |
| 117 | 121 | |
| 118 | 122 | // 通过 deviceId 获取设备信息 |
| 119 | - IotDeviceCacheService.DeviceInfo deviceInfo = deviceCacheService.getDeviceInfoById(message.getDeviceId()); | |
| 123 | + IotDeviceGetReqDTO reqDTO = new IotDeviceGetReqDTO(); | |
| 124 | + reqDTO.setId(message.getDeviceId()); | |
| 125 | + IotDeviceRespDTO deviceInfo = deviceApi.getDevice(reqDTO).getData(); | |
| 120 | 126 | if (deviceInfo == null) { |
| 121 | 127 | log.warn("[handleServiceMessage][设备信息不存在][deviceId: {}]", message.getDeviceId()); |
| 122 | 128 | return; |
| ... | ... | @@ -141,7 +147,9 @@ public class IotMqttDownstreamSubscriber implements IotMessageSubscriber<IotDevi |
| 141 | 147 | */ |
| 142 | 148 | private void handleConfigMessage(IotDeviceMessage message) { |
| 143 | 149 | // 通过 deviceId 获取设备信息 |
| 144 | - IotDeviceCacheService.DeviceInfo deviceInfo = deviceCacheService.getDeviceInfoById(message.getDeviceId()); | |
| 150 | + IotDeviceGetReqDTO reqDTO = new IotDeviceGetReqDTO(); | |
| 151 | + reqDTO.setId(message.getDeviceId()); | |
| 152 | + IotDeviceRespDTO deviceInfo = deviceApi.getDevice(reqDTO).getData(); | |
| 145 | 153 | if (deviceInfo == null) { |
| 146 | 154 | log.warn("[handleConfigMessage][设备信息不存在][deviceId: {}]", message.getDeviceId()); |
| 147 | 155 | return; |
| ... | ... | @@ -163,7 +171,9 @@ public class IotMqttDownstreamSubscriber implements IotMessageSubscriber<IotDevi |
| 163 | 171 | */ |
| 164 | 172 | private void handleOtaMessage(IotDeviceMessage message) { |
| 165 | 173 | // 通过 deviceId 获取设备信息 |
| 166 | - IotDeviceCacheService.DeviceInfo deviceInfo = deviceCacheService.getDeviceInfoById(message.getDeviceId()); | |
| 174 | + IotDeviceGetReqDTO reqDTO = new IotDeviceGetReqDTO(); | |
| 175 | + reqDTO.setId(message.getDeviceId()); | |
| 176 | + IotDeviceRespDTO deviceInfo = deviceApi.getDevice(reqDTO).getData(); | |
| 167 | 177 | if (deviceInfo == null) { |
| 168 | 178 | log.warn("[handleOtaMessage][设备信息不存在][deviceId: {}]", message.getDeviceId()); |
| 169 | 179 | return; | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/IotMqttHttpAuthProtocol.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.gateway.protocol.mqtt; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties; | |
| 4 | +import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttHttpAuthHandler; | |
| 5 | +import io.vertx.core.AbstractVerticle; | |
| 6 | +import io.vertx.core.Vertx; | |
| 7 | +import io.vertx.core.http.HttpServer; | |
| 8 | +import io.vertx.ext.web.Router; | |
| 9 | +import io.vertx.ext.web.handler.BodyHandler; | |
| 10 | +import jakarta.annotation.PostConstruct; | |
| 11 | +import jakarta.annotation.PreDestroy; | |
| 12 | +import lombok.RequiredArgsConstructor; | |
| 13 | +import lombok.extern.slf4j.Slf4j; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * IoT 网关 MQTT HTTP 认证协议:提供 HTTP 认证接口供 EMQX 调用 | |
| 17 | + * | |
| 18 | + * @author 芋道源码 | |
| 19 | + */ | |
| 20 | +@RequiredArgsConstructor | |
| 21 | +@Slf4j | |
| 22 | +public class IotMqttHttpAuthProtocol extends AbstractVerticle { | |
| 23 | + | |
| 24 | + private final IotGatewayProperties.EmqxProperties emqxProperties; | |
| 25 | + | |
| 26 | + private HttpServer httpServer; | |
| 27 | + private Vertx vertx; | |
| 28 | + | |
| 29 | + @Override | |
| 30 | + @PostConstruct | |
| 31 | + public void start() { | |
| 32 | + log.info("[start][开始启动 MQTT HTTP 认证协议服务]"); | |
| 33 | + | |
| 34 | + // 创建 Vertx 实例 | |
| 35 | + this.vertx = Vertx.vertx(); | |
| 36 | + | |
| 37 | + // 创建路由 | |
| 38 | + Router router = Router.router(vertx); | |
| 39 | + router.route().handler(BodyHandler.create()); | |
| 40 | + | |
| 41 | + // 创建 MQTT 认证处理器 | |
| 42 | + IotMqttHttpAuthHandler authHandler = new IotMqttHttpAuthHandler(); | |
| 43 | + | |
| 44 | + // 添加 MQTT 认证路由 | |
| 45 | + router.post("/mqtt/auth/authenticate").handler(authHandler::authenticate); | |
| 46 | + router.post("/mqtt/auth/connected").handler(authHandler::connected); | |
| 47 | + router.post("/mqtt/auth/disconnected").handler(authHandler::disconnected); | |
| 48 | + | |
| 49 | + // 启动 HTTP 服务器,使用独立端口 | |
| 50 | + int authPort = getAuthPort(); | |
| 51 | + try { | |
| 52 | + httpServer = vertx.createHttpServer() | |
| 53 | + .requestHandler(router) | |
| 54 | + .listen(authPort) | |
| 55 | + .result(); | |
| 56 | + log.info("[start][MQTT HTTP 认证协议启动成功,端口:{}]", authPort); | |
| 57 | + } catch (Exception e) { | |
| 58 | + log.error("[start][MQTT HTTP 认证协议启动失败]", e); | |
| 59 | + throw e; | |
| 60 | + } | |
| 61 | + } | |
| 62 | + | |
| 63 | + @Override | |
| 64 | + @PreDestroy | |
| 65 | + public void stop() { | |
| 66 | + if (httpServer != null) { | |
| 67 | + try { | |
| 68 | + httpServer.close().result(); | |
| 69 | + log.info("[stop][MQTT HTTP 认证协议已停止]"); | |
| 70 | + } catch (Exception e) { | |
| 71 | + log.error("[stop][MQTT HTTP 认证协议停止失败]", e); | |
| 72 | + } | |
| 73 | + } | |
| 74 | + | |
| 75 | + if (vertx != null) { | |
| 76 | + try { | |
| 77 | + vertx.close(); | |
| 78 | + log.info("[stop][Vertx 已关闭]"); | |
| 79 | + } catch (Exception e) { | |
| 80 | + log.warn("[stop][关闭 Vertx 异常]", e); | |
| 81 | + } | |
| 82 | + } | |
| 83 | + } | |
| 84 | + | |
| 85 | + /** | |
| 86 | + * 获取认证服务端口 | |
| 87 | + * 从配置中获取,默认使用 8090 端口 | |
| 88 | + */ | |
| 89 | + private int getAuthPort() { | |
| 90 | + return emqxProperties.getHttpAuthPort() != null ? emqxProperties.getHttpAuthPort() : 8090; | |
| 91 | + } | |
| 92 | + | |
| 93 | + public String getServerId() { | |
| 94 | + return "mqtt_auth_gateway_" + getAuthPort(); | |
| 95 | + } | |
| 96 | +} | |
| 0 | 97 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/IotMqttUpstreamProtocol.http
0 → 100644
| 1 | +### IoT MQTT HTTP 认证服务测试文件 | |
| 2 | +### 用于测试独立的 MQTT HTTP 认证服务接口 | |
| 3 | +### 服务由 IotMqttHttpAuthProtocol 启动,运行在配置的端口上(默认 8090) | |
| 4 | +### 注意:这些接口通常由 EMQX 调用,也可以用于手动测试 | |
| 5 | + | |
| 6 | +### 配置说明: | |
| 7 | +### 在 application-local.yaml 中可以配置端口: | |
| 8 | +### yudao: | |
| 9 | +### iot: | |
| 10 | +### gateway: | |
| 11 | +### protocol: | |
| 12 | +### emqx: | |
| 13 | +### http-auth-port: 8090 # 可以修改为其他端口 | |
| 14 | + | |
| 15 | +### 1. MQTT 设备认证接口 => 成功认证 | |
| 16 | +POST http://localhost:8090/mqtt/auth/authenticate | |
| 17 | +Content-Type: application/json | |
| 18 | + | |
| 19 | +{ | |
| 20 | + "clientid": "test_product.test_device", | |
| 21 | + "username": "test_device&test_product", | |
| 22 | + "password": "test_device_secret_hmac_password" | |
| 23 | +} | |
| 24 | + | |
| 25 | +### 2. MQTT 设备认证接口 => 参数不完整(clientid 为空) | |
| 26 | +POST http://localhost:8090/mqtt/auth/authenticate | |
| 27 | +Content-Type: application/json | |
| 28 | + | |
| 29 | +{ | |
| 30 | + "clientid": "", | |
| 31 | + "username": "test_device&test_product", | |
| 32 | + "password": "test_device_secret" | |
| 33 | +} | |
| 34 | + | |
| 35 | +### 3. MQTT 设备认证接口 => 参数不完整(username 为空) | |
| 36 | +POST http://localhost:8090/mqtt/auth/authenticate | |
| 37 | +Content-Type: application/json | |
| 38 | + | |
| 39 | +{ | |
| 40 | + "clientid": "test_product.test_device", | |
| 41 | + "username": "", | |
| 42 | + "password": "test_device_secret" | |
| 43 | +} | |
| 44 | + | |
| 45 | +### 4. MQTT 设备认证接口 => 参数不完整(password 为空) | |
| 46 | +POST http://localhost:8090/mqtt/auth/authenticate | |
| 47 | +Content-Type: application/json | |
| 48 | + | |
| 49 | +{ | |
| 50 | + "clientid": "test_product.test_device", | |
| 51 | + "username": "test_device&test_product", | |
| 52 | + "password": "" | |
| 53 | +} | |
| 54 | + | |
| 55 | +### 5. MQTT 设备认证接口 => 认证失败(错误的设备密钥) | |
| 56 | +POST http://localhost:8090/mqtt/auth/authenticate | |
| 57 | +Content-Type: application/json | |
| 58 | + | |
| 59 | +{ | |
| 60 | + "clientid": "test_product.test_device", | |
| 61 | + "username": "test_device&test_product", | |
| 62 | + "password": "wrong_password" | |
| 63 | +} | |
| 64 | + | |
| 65 | +### 6. EMQX 客户端连接事件钩子 => 设备上线 | |
| 66 | +POST http://localhost:8090/mqtt/auth/connected | |
| 67 | +Content-Type: application/json | |
| 68 | + | |
| 69 | +{ | |
| 70 | + "clientid": "test_product.test_device", | |
| 71 | + "username": "test_device&test_product", | |
| 72 | + "timestamp": 1703808000000, | |
| 73 | + "peername": "192.168.1.100:52036", | |
| 74 | + "sockname": "127.0.0.1:1883" | |
| 75 | +} | |
| 76 | + | |
| 77 | +### 7. EMQX 客户端连接事件钩子 => 用户名为空 | |
| 78 | +POST http://localhost:8090/mqtt/auth/connected | |
| 79 | +Content-Type: application/json | |
| 80 | + | |
| 81 | +{ | |
| 82 | + "clientid": "test_product.test_device", | |
| 83 | + "username": "", | |
| 84 | + "timestamp": 1703808000000, | |
| 85 | + "peername": "192.168.1.100:52036", | |
| 86 | + "sockname": "127.0.0.1:1883" | |
| 87 | +} | |
| 88 | + | |
| 89 | +### 8. EMQX 客户端断开连接事件钩子 => 设备下线(正常断开) | |
| 90 | +POST http://localhost:8090/mqtt/auth/disconnected | |
| 91 | +Content-Type: application/json | |
| 92 | + | |
| 93 | +{ | |
| 94 | + "clientid": "test_product.test_device", | |
| 95 | + "username": "test_device&test_product", | |
| 96 | + "reason": "normal", | |
| 97 | + "timestamp": 1703808060000 | |
| 98 | +} | |
| 99 | + | |
| 100 | +### 9. 使用自定义端口测试(如果配置了不同端口) | |
| 101 | +### 假设配置了端口 8091: | |
| 102 | +### POST http://localhost:8091/mqtt/auth/authenticate | |
| 103 | +### Content-Type: application/json | |
| 104 | +### | |
| 105 | +### { | |
| 106 | +### "clientid": "test_product.test_device", | |
| 107 | +### "username": "test_device&test_product", | |
| 108 | +### "password": "test_device_secret_hmac_password" | |
| 109 | +### } | |
| 110 | + | |
| 111 | +### EMQX 配置参考: | |
| 112 | +### authentication = [ | |
| 113 | +### { | |
| 114 | +### mechanism = http | |
| 115 | +### method = post | |
| 116 | +### url = "http://localhost:8090/mqtt/auth/authenticate" # 使用配置的端口 | |
| 117 | +### body = { | |
| 118 | +### clientid = "${clientid}" | |
| 119 | +### username = "${username}" | |
| 120 | +### password = "${password}" | |
| 121 | +### } | |
| 122 | +### headers = { | |
| 123 | +### "content-type" = "application/json" | |
| 124 | +### } | |
| 125 | +### } | |
| 126 | +### ] | |
| 127 | +### | |
| 128 | +### webhooks = [ | |
| 129 | +### { | |
| 130 | +### name = "client_connected" | |
| 131 | +### url = "http://localhost:8090/mqtt/auth/connected" # 使用配置的端口 | |
| 132 | +### events = ["client.connected"] | |
| 133 | +### }, | |
| 134 | +### { | |
| 135 | +### name = "client_disconnected" | |
| 136 | +### url = "http://localhost:8090/mqtt/auth/disconnected" # 使用配置的端口 | |
| 137 | +### events = ["client.disconnected"] | |
| 138 | +### } | |
| 139 | +### ] | |
| 0 | 140 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/IotMqttUpstreamProtocol.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.gateway.protocol.mqtt; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | -import cn.hutool.core.util.ArrayUtil; | |
| 5 | 4 | import cn.hutool.core.util.IdUtil; |
| 6 | 5 | import cn.hutool.core.util.ObjUtil; |
| 7 | 6 | import cn.hutool.core.util.StrUtil; |
| 8 | -import cn.hutool.extra.spring.SpringUtil; | |
| 9 | -import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | |
| 10 | 7 | import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; |
| 11 | 8 | import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties; |
| 12 | -import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttAuthRouter; | |
| 13 | 9 | import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttUpstreamRouter; |
| 14 | 10 | import io.netty.handler.codec.mqtt.MqttQoS; |
| 15 | 11 | import io.vertx.core.Vertx; |
| ... | ... | @@ -43,8 +39,6 @@ public class IotMqttUpstreamProtocol { |
| 43 | 39 | private Vertx vertx; |
| 44 | 40 | private MqttClient mqttClient; |
| 45 | 41 | private IotMqttUpstreamRouter messageRouter; |
| 46 | - private IotMqttAuthRouter authRouter; | |
| 47 | - private IotDeviceMessageProducer deviceMessageProducer; | |
| 48 | 42 | |
| 49 | 43 | /** |
| 50 | 44 | * 服务运行状态标志 |
| ... | ... | @@ -61,9 +55,7 @@ public class IotMqttUpstreamProtocol { |
| 61 | 55 | |
| 62 | 56 | // 初始化组件 |
| 63 | 57 | this.vertx = Vertx.vertx(); |
| 64 | - this.deviceMessageProducer = SpringUtil.getBean(IotDeviceMessageProducer.class); | |
| 65 | 58 | this.messageRouter = new IotMqttUpstreamRouter(this); |
| 66 | - this.authRouter = new IotMqttAuthRouter(this); | |
| 67 | 59 | |
| 68 | 60 | // 创建 MQTT 客户端 |
| 69 | 61 | MqttClientOptions options = new MqttClientOptions() |
| ... | ... | @@ -255,13 +247,4 @@ public class IotMqttUpstreamProtocol { |
| 255 | 247 | return mqttClient; |
| 256 | 248 | } |
| 257 | 249 | |
| 258 | - /** | |
| 259 | - * 获取认证路由器 | |
| 260 | - * | |
| 261 | - * @return 认证路由器 | |
| 262 | - */ | |
| 263 | - public IotMqttAuthRouter getAuthRouter() { | |
| 264 | - return authRouter; | |
| 265 | - } | |
| 266 | - | |
| 267 | 250 | } |
| 268 | 251 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/IotMqttAuthRouter.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router; | |
| 2 | - | |
| 3 | -import cn.hutool.core.util.StrUtil; | |
| 4 | -import cn.hutool.extra.spring.SpringUtil; | |
| 5 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 6 | -import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; | |
| 7 | -import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; | |
| 8 | -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | |
| 9 | -import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; | |
| 10 | -import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; | |
| 11 | -import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttUpstreamProtocol; | |
| 12 | -import cn.iocoder.yudao.module.iot.gateway.service.auth.IotDeviceTokenService; | |
| 13 | -import cn.iocoder.yudao.module.iot.gateway.service.message.IotDeviceMessageService; | |
| 14 | -import lombok.RequiredArgsConstructor; | |
| 15 | -import lombok.extern.slf4j.Slf4j; | |
| 16 | - | |
| 17 | -/** | |
| 18 | - * IoT 网关 MQTT 认证路由器 | |
| 19 | - * <p> | |
| 20 | - * 处理设备的 MQTT 连接认证和连接状态管理 | |
| 21 | - * | |
| 22 | - * @author 芋道源码 | |
| 23 | - */ | |
| 24 | -@RequiredArgsConstructor | |
| 25 | -@Slf4j | |
| 26 | -public class IotMqttAuthRouter { | |
| 27 | - | |
| 28 | - private final IotMqttUpstreamProtocol protocol; | |
| 29 | - private final IotDeviceMessageProducer deviceMessageProducer; | |
| 30 | - private final IotDeviceTokenService deviceTokenService; | |
| 31 | - private final IotDeviceCommonApi deviceCommonApi; | |
| 32 | - private final IotDeviceMessageService deviceMessageService; | |
| 33 | - | |
| 34 | - public IotMqttAuthRouter(IotMqttUpstreamProtocol protocol) { | |
| 35 | - this.protocol = protocol; | |
| 36 | - this.deviceMessageProducer = SpringUtil.getBean(IotDeviceMessageProducer.class); | |
| 37 | - this.deviceTokenService = SpringUtil.getBean(IotDeviceTokenService.class); | |
| 38 | - this.deviceCommonApi = SpringUtil.getBean(IotDeviceCommonApi.class); | |
| 39 | - this.deviceMessageService = SpringUtil.getBean(IotDeviceMessageService.class); | |
| 40 | - } | |
| 41 | - | |
| 42 | - /** | |
| 43 | - * 处理设备认证 | |
| 44 | - * | |
| 45 | - * @param clientId 客户端 ID | |
| 46 | - * @param username 用户名 | |
| 47 | - * @param password 密码 | |
| 48 | - * @return 认证结果 | |
| 49 | - */ | |
| 50 | - public boolean authenticate(String clientId, String username, String password) { | |
| 51 | - try { | |
| 52 | - log.info("[authenticate][开始认证设备][clientId: {}][username: {}]", clientId, username); | |
| 53 | - | |
| 54 | - // 1. 参数校验 | |
| 55 | - if (StrUtil.isEmpty(clientId) || StrUtil.isEmpty(username) || StrUtil.isEmpty(password)) { | |
| 56 | - log.warn("[authenticate][认证参数不完整][clientId: {}][username: {}]", clientId, username); | |
| 57 | - return false; | |
| 58 | - } | |
| 59 | - | |
| 60 | - // 2. 执行认证 | |
| 61 | - CommonResult<Boolean> result = deviceCommonApi.authDevice(new IotDeviceAuthReqDTO() | |
| 62 | - .setClientId(clientId).setUsername(username).setPassword(password)); | |
| 63 | - result.checkError(); | |
| 64 | - if (!Boolean.TRUE.equals(result.getData())) { | |
| 65 | - log.warn("[authenticate][设备认证失败][clientId: {}][username: {}]", clientId, username); | |
| 66 | - return false; | |
| 67 | - } | |
| 68 | - | |
| 69 | - log.info("[authenticate][设备认证成功][clientId: {}][username: {}]", clientId, username); | |
| 70 | - return true; | |
| 71 | - } catch (Exception e) { | |
| 72 | - log.error("[authenticate][设备认证异常][clientId: {}][username: {}]", clientId, username, e); | |
| 73 | - return false; | |
| 74 | - } | |
| 75 | - } | |
| 76 | - | |
| 77 | - /** | |
| 78 | - * 处理设备连接事件 | |
| 79 | - * | |
| 80 | - * @param clientId 客户端 ID | |
| 81 | - * @param username 用户名 | |
| 82 | - */ | |
| 83 | - public void handleClientConnected(String clientId, String username) { | |
| 84 | - try { | |
| 85 | - log.info("[handleClientConnected][设备连接][clientId: {}][username: {}]", clientId, username); | |
| 86 | - | |
| 87 | - // 解析设备信息并发送上线消息 | |
| 88 | - handleDeviceStateChange(username, true); | |
| 89 | - } catch (Exception e) { | |
| 90 | - log.error("[handleClientConnected][处理设备连接事件异常][clientId: {}][username: {}]", clientId, username, e); | |
| 91 | - } | |
| 92 | - } | |
| 93 | - | |
| 94 | - /** | |
| 95 | - * 处理设备断开连接事件 | |
| 96 | - * | |
| 97 | - * @param clientId 客户端 ID | |
| 98 | - * @param username 用户名 | |
| 99 | - */ | |
| 100 | - public void handleClientDisconnected(String clientId, String username) { | |
| 101 | - try { | |
| 102 | - log.info("[handleClientDisconnected][设备断开连接][clientId: {}][username: {}]", clientId, username); | |
| 103 | - | |
| 104 | - // 解析设备信息并发送下线消息 | |
| 105 | - handleDeviceStateChange(username, false); | |
| 106 | - } catch (Exception e) { | |
| 107 | - log.error("[handleClientDisconnected][处理设备断开连接事件异常][clientId: {}][username: {}]", clientId, username, e); | |
| 108 | - } | |
| 109 | - } | |
| 110 | - | |
| 111 | - /** | |
| 112 | - * 处理设备状态变化 | |
| 113 | - * | |
| 114 | - * @param username 用户名 | |
| 115 | - * @param online 是否在线 | |
| 116 | - */ | |
| 117 | - private void handleDeviceStateChange(String username, boolean online) { | |
| 118 | - // 解析设备信息 | |
| 119 | - if (StrUtil.isEmpty(username) || "undefined".equals(username)) { | |
| 120 | - log.warn("[handleDeviceStateChange][用户名为空或未定义][username: {}]", username); | |
| 121 | - return; | |
| 122 | - } | |
| 123 | - | |
| 124 | - IotDeviceAuthUtils.DeviceInfo deviceInfo = deviceTokenService.parseUsername(username); | |
| 125 | - if (deviceInfo == null) { | |
| 126 | - log.warn("[handleDeviceStateChange][无法解析设备信息][username: {}]", username); | |
| 127 | - return; | |
| 128 | - } | |
| 129 | - | |
| 130 | - try { | |
| 131 | - // 使用 IotDeviceMessageService 构建设备状态消息 | |
| 132 | - IotDeviceMessage message; | |
| 133 | - if (online) { | |
| 134 | - message = deviceMessageService.buildDeviceMessageOfStateOnline( | |
| 135 | - deviceInfo.getProductKey(), deviceInfo.getDeviceName(), protocol.getServerId()); | |
| 136 | - log.info("[handleDeviceStateChange][发送设备上线消息成功][username: {}]", username); | |
| 137 | - } else { | |
| 138 | - message = deviceMessageService.buildDeviceMessageOfStateOffline( | |
| 139 | - deviceInfo.getProductKey(), deviceInfo.getDeviceName(), protocol.getServerId()); | |
| 140 | - log.info("[handleDeviceStateChange][发送设备下线消息成功][username: {}]", username); | |
| 141 | - } | |
| 142 | - | |
| 143 | - deviceMessageProducer.sendDeviceMessage(message); | |
| 144 | - } catch (Exception e) { | |
| 145 | - log.error("[handleDeviceStateChange][发送设备状态消息失败][username: {}][online: {}]", username, online, e); | |
| 146 | - } | |
| 147 | - } | |
| 148 | - | |
| 149 | -} | |
| 150 | 0 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/IotMqttEventHandler.java
| ... | ... | @@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 6 | 6 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; |
| 7 | 7 | import cn.iocoder.yudao.module.iot.gateway.enums.IotDeviceTopicEnum; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttUpstreamProtocol; |
| 9 | -import cn.iocoder.yudao.module.iot.gateway.service.message.IotDeviceMessageService; | |
| 9 | +import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; | |
| 10 | 10 | import lombok.RequiredArgsConstructor; |
| 11 | 11 | import lombok.extern.slf4j.Slf4j; |
| 12 | 12 | |
| ... | ... | @@ -49,7 +49,7 @@ public class IotMqttEventHandler extends IotMqttAbstractHandler { |
| 49 | 49 | // 使用 IotDeviceMessageService 解码消息 |
| 50 | 50 | byte[] messageBytes = payload.getBytes(StandardCharsets.UTF_8); |
| 51 | 51 | IotDeviceMessage message = deviceMessageService.decodeDeviceMessage( |
| 52 | - messageBytes, productKey, deviceName, protocol.getServerId()); | |
| 52 | + messageBytes, productKey, deviceName); | |
| 53 | 53 | |
| 54 | 54 | // 发送消息 |
| 55 | 55 | deviceMessageProducer.sendDeviceMessage(message); | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/IotMqttHttpAuthHandler.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.BooleanUtil; | |
| 4 | +import cn.hutool.core.util.StrUtil; | |
| 5 | +import cn.hutool.extra.spring.SpringUtil; | |
| 6 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 7 | +import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; | |
| 8 | +import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO; | |
| 9 | +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; | |
| 10 | +import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils; | |
| 11 | +import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; | |
| 12 | +import io.vertx.core.json.JsonObject; | |
| 13 | +import io.vertx.ext.web.RoutingContext; | |
| 14 | +import lombok.extern.slf4j.Slf4j; | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * IoT 网关 MQTT HTTP 认证处理器 | |
| 18 | + * <p> | |
| 19 | + * 处理 EMQX 的认证请求和事件钩子 | |
| 20 | + * | |
| 21 | + * @author 芋道源码 | |
| 22 | + */ | |
| 23 | +@Slf4j | |
| 24 | +public class IotMqttHttpAuthHandler { | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * EMQX 认证接口 | |
| 28 | + */ | |
| 29 | + public void authenticate(RoutingContext context) { | |
| 30 | + try { | |
| 31 | + // 解析请求体 | |
| 32 | + JsonObject body = context.body().asJsonObject(); | |
| 33 | + if (body == null) { | |
| 34 | + sendErrorResponse(context, 400, "请求体不能为空"); | |
| 35 | + return; | |
| 36 | + } | |
| 37 | + | |
| 38 | + String clientid = body.getString("clientid"); | |
| 39 | + String username = body.getString("username"); | |
| 40 | + String password = body.getString("password"); | |
| 41 | + | |
| 42 | + log.info("[authenticate][EMQX 设备认证请求][clientId: {}][username: {}]", clientid, username); | |
| 43 | + | |
| 44 | + // 参数校验 | |
| 45 | + if (StrUtil.isEmpty(clientid) || StrUtil.isEmpty(username) || StrUtil.isEmpty(password)) { | |
| 46 | + log.warn("[authenticate][认证参数不完整][clientId: {}][username: {}]", clientid, username); | |
| 47 | + sendErrorResponse(context, 400, "认证参数不完整"); | |
| 48 | + return; | |
| 49 | + } | |
| 50 | + | |
| 51 | + // 执行设备认证 | |
| 52 | + IotDeviceCommonApi deviceApi = SpringUtil.getBean(IotDeviceCommonApi.class); | |
| 53 | + CommonResult<Boolean> result = deviceApi.authDevice(new IotDeviceAuthReqDTO() | |
| 54 | + .setClientId(clientid) | |
| 55 | + .setUsername(username) | |
| 56 | + .setPassword(password)); | |
| 57 | + | |
| 58 | + result.checkError(); | |
| 59 | + if (!BooleanUtil.isTrue(result.getData())) { | |
| 60 | + log.warn("[authenticate][设备认证失败][clientId: {}][username: {}]", clientid, username); | |
| 61 | + sendErrorResponse(context, 401, "设备认证失败"); | |
| 62 | + return; | |
| 63 | + } | |
| 64 | + | |
| 65 | + log.info("[authenticate][设备认证成功][clientId: {}][username: {}]", clientid, username); | |
| 66 | + sendSuccessResponse(context, "认证成功"); | |
| 67 | + | |
| 68 | + } catch (Exception e) { | |
| 69 | + log.error("[authenticate][设备认证异常]", e); | |
| 70 | + sendErrorResponse(context, 500, "认证服务异常"); | |
| 71 | + } | |
| 72 | + } | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * EMQX 客户端连接事件钩子 | |
| 76 | + */ | |
| 77 | + public void connected(RoutingContext context) { | |
| 78 | + try { | |
| 79 | + // 解析请求体 | |
| 80 | + JsonObject body = context.body().asJsonObject(); | |
| 81 | + if (body == null) { | |
| 82 | + sendErrorResponse(context, 400, "请求体不能为空"); | |
| 83 | + return; | |
| 84 | + } | |
| 85 | + | |
| 86 | + String clientid = body.getString("clientid"); | |
| 87 | + String username = body.getString("username"); | |
| 88 | + Long timestamp = body.getLong("timestamp"); | |
| 89 | + | |
| 90 | + log.info("[connected][设备连接事件][clientId: {}][username: {}]", clientid, username); | |
| 91 | + | |
| 92 | + handleDeviceStateChange(username, true); | |
| 93 | + sendSuccessResponse(context, "处理成功"); | |
| 94 | + | |
| 95 | + } catch (Exception e) { | |
| 96 | + log.error("[connected][处理设备连接事件失败]", e); | |
| 97 | + sendErrorResponse(context, 500, "处理失败"); | |
| 98 | + } | |
| 99 | + } | |
| 100 | + | |
| 101 | + /** | |
| 102 | + * EMQX 客户端断开连接事件钩子 | |
| 103 | + */ | |
| 104 | + public void disconnected(RoutingContext context) { | |
| 105 | + try { | |
| 106 | + // 解析请求体 | |
| 107 | + JsonObject body = context.body().asJsonObject(); | |
| 108 | + if (body == null) { | |
| 109 | + sendErrorResponse(context, 400, "请求体不能为空"); | |
| 110 | + return; | |
| 111 | + } | |
| 112 | + | |
| 113 | + String clientid = body.getString("clientid"); | |
| 114 | + String username = body.getString("username"); | |
| 115 | + String reason = body.getString("reason"); | |
| 116 | + Long timestamp = body.getLong("timestamp"); | |
| 117 | + | |
| 118 | + log.info("[disconnected][设备断开连接事件][clientId: {}][username: {}][reason: {}]", | |
| 119 | + clientid, username, reason); | |
| 120 | + | |
| 121 | + handleDeviceStateChange(username, false); | |
| 122 | + sendSuccessResponse(context, "处理成功"); | |
| 123 | + | |
| 124 | + } catch (Exception e) { | |
| 125 | + log.error("[disconnected][处理设备断开连接事件失败]", e); | |
| 126 | + sendErrorResponse(context, 500, "处理失败"); | |
| 127 | + } | |
| 128 | + } | |
| 129 | + | |
| 130 | + /** | |
| 131 | + * 处理设备状态变化 | |
| 132 | + * | |
| 133 | + * @param username 用户名 | |
| 134 | + * @param online 是否在线 | |
| 135 | + */ | |
| 136 | + private void handleDeviceStateChange(String username, boolean online) { | |
| 137 | + if (StrUtil.isEmpty(username) || "undefined".equals(username)) { | |
| 138 | + log.warn("[handleDeviceStateChange][用户名为空或未定义][username: {}]", username); | |
| 139 | + return; | |
| 140 | + } | |
| 141 | + | |
| 142 | + // 解析设备信息 | |
| 143 | + IotDeviceAuthUtils.DeviceInfo deviceInfo = IotDeviceAuthUtils.parseUsername(username); | |
| 144 | + if (deviceInfo == null) { | |
| 145 | + log.warn("[handleDeviceStateChange][无法解析设备信息][username: {}]", username); | |
| 146 | + return; | |
| 147 | + } | |
| 148 | + | |
| 149 | + try { | |
| 150 | + // 获取服务器 ID | |
| 151 | + String serverId = "mqtt_auth_gateway"; | |
| 152 | + | |
| 153 | + // 构建设备状态消息 | |
| 154 | + IotDeviceMessageService deviceMessageService = SpringUtil.getBean(IotDeviceMessageService.class); | |
| 155 | + IotDeviceMessage message; | |
| 156 | + if (online) { | |
| 157 | + message = IotDeviceMessage.buildStateOnline(); | |
| 158 | + log.info("[handleDeviceStateChange][发送设备上线消息成功][username: {}]", username); | |
| 159 | + } else { | |
| 160 | + message = IotDeviceMessage.buildStateOffline(); | |
| 161 | + log.info("[handleDeviceStateChange][发送设备下线消息成功][username: {}]", username); | |
| 162 | + } | |
| 163 | + | |
| 164 | + // 发送消息到消息总线 | |
| 165 | + deviceMessageService.sendDeviceMessage(message, | |
| 166 | + deviceInfo.getProductKey(), deviceInfo.getDeviceName(), serverId); | |
| 167 | + } catch (Exception e) { | |
| 168 | + log.error("[handleDeviceStateChange][发送设备状态消息失败][username: {}][online: {}]", | |
| 169 | + username, online, e); | |
| 170 | + } | |
| 171 | + } | |
| 172 | + | |
| 173 | + /** | |
| 174 | + * 发送成功响应 | |
| 175 | + */ | |
| 176 | + private void sendSuccessResponse(RoutingContext context, String message) { | |
| 177 | + context.response() | |
| 178 | + .setStatusCode(200) | |
| 179 | + .putHeader("Content-Type", "text/plain; charset=utf-8") | |
| 180 | + .end(message); | |
| 181 | + } | |
| 182 | + | |
| 183 | + /** | |
| 184 | + * 发送错误响应 | |
| 185 | + */ | |
| 186 | + private void sendErrorResponse(RoutingContext context, int statusCode, String message) { | |
| 187 | + context.response() | |
| 188 | + .setStatusCode(statusCode) | |
| 189 | + .putHeader("Content-Type", "text/plain; charset=utf-8") | |
| 190 | + .end(message); | |
| 191 | + } | |
| 192 | +} | |
| 0 | 193 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/IotMqttPropertyHandler.java
| ... | ... | @@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 6 | 6 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; |
| 7 | 7 | import cn.iocoder.yudao.module.iot.gateway.enums.IotDeviceTopicEnum; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttUpstreamProtocol; |
| 9 | -import cn.iocoder.yudao.module.iot.gateway.service.message.IotDeviceMessageService; | |
| 9 | +import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; | |
| 10 | 10 | import lombok.RequiredArgsConstructor; |
| 11 | 11 | import lombok.extern.slf4j.Slf4j; |
| 12 | 12 | |
| ... | ... | @@ -65,7 +65,7 @@ public class IotMqttPropertyHandler extends IotMqttAbstractHandler { |
| 65 | 65 | // 使用 IotDeviceMessageService 解码消息 |
| 66 | 66 | byte[] messageBytes = payload.getBytes(StandardCharsets.UTF_8); |
| 67 | 67 | IotDeviceMessage message = deviceMessageService.decodeDeviceMessage( |
| 68 | - messageBytes, productKey, deviceName, protocol.getServerId()); | |
| 68 | + messageBytes, productKey, deviceName); | |
| 69 | 69 | |
| 70 | 70 | // 发送消息 |
| 71 | 71 | deviceMessageProducer.sendDeviceMessage(message); |
| ... | ... | @@ -100,7 +100,7 @@ public class IotMqttPropertyHandler extends IotMqttAbstractHandler { |
| 100 | 100 | // 使用 IotDeviceMessageService 解码消息 |
| 101 | 101 | byte[] messageBytes = payload.getBytes(StandardCharsets.UTF_8); |
| 102 | 102 | IotDeviceMessage message = deviceMessageService.decodeDeviceMessage( |
| 103 | - messageBytes, productKey, deviceName, protocol.getServerId()); | |
| 103 | + messageBytes, productKey, deviceName); | |
| 104 | 104 | |
| 105 | 105 | // 发送消息 |
| 106 | 106 | deviceMessageProducer.sendDeviceMessage(message); |
| ... | ... | @@ -132,7 +132,7 @@ public class IotMqttPropertyHandler extends IotMqttAbstractHandler { |
| 132 | 132 | // 使用 IotDeviceMessageService 解码消息 |
| 133 | 133 | byte[] messageBytes = payload.getBytes(StandardCharsets.UTF_8); |
| 134 | 134 | IotDeviceMessage message = deviceMessageService.decodeDeviceMessage( |
| 135 | - messageBytes, productKey, deviceName, protocol.getServerId()); | |
| 135 | + messageBytes, productKey, deviceName); | |
| 136 | 136 | |
| 137 | 137 | // 发送消息 |
| 138 | 138 | deviceMessageProducer.sendDeviceMessage(message); | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/IotMqttServiceHandler.java
| ... | ... | @@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 6 | 6 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; |
| 7 | 7 | import cn.iocoder.yudao.module.iot.gateway.enums.IotDeviceTopicEnum; |
| 8 | 8 | import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttUpstreamProtocol; |
| 9 | -import cn.iocoder.yudao.module.iot.gateway.service.message.IotDeviceMessageService; | |
| 9 | +import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; | |
| 10 | 10 | import lombok.RequiredArgsConstructor; |
| 11 | 11 | import lombok.extern.slf4j.Slf4j; |
| 12 | 12 | |
| ... | ... | @@ -49,7 +49,7 @@ public class IotMqttServiceHandler extends IotMqttAbstractHandler { |
| 49 | 49 | // 使用 IotDeviceMessageService 解码消息 |
| 50 | 50 | byte[] messageBytes = payload.getBytes(StandardCharsets.UTF_8); |
| 51 | 51 | IotDeviceMessage message = deviceMessageService.decodeDeviceMessage( |
| 52 | - messageBytes, productKey, deviceName, protocol.getServerId()); | |
| 52 | + messageBytes, productKey, deviceName); | |
| 53 | 53 | |
| 54 | 54 | // 发送消息 |
| 55 | 55 | deviceMessageProducer.sendDeviceMessage(message); | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/IotMqttUpstreamRouter.java
| ... | ... | @@ -5,7 +5,7 @@ import cn.hutool.extra.spring.SpringUtil; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer; |
| 6 | 6 | import cn.iocoder.yudao.module.iot.gateway.enums.IotDeviceTopicEnum; |
| 7 | 7 | import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttUpstreamProtocol; |
| 8 | -import cn.iocoder.yudao.module.iot.gateway.service.message.IotDeviceMessageService; | |
| 8 | +import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; | |
| 9 | 9 | import io.vertx.mqtt.messages.MqttPublishMessage; |
| 10 | 10 | import lombok.RequiredArgsConstructor; |
| 11 | 11 | import lombok.extern.slf4j.Slf4j; | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application-local.yaml
| 1 | -server: | |
| 2 | - port: 8090 # IoT 网关服务端口 | |
| 1 | +# ==================== IoT 网关本地开发环境配置 ==================== | |
| 3 | 2 | |
| 4 | 3 | --- #################### 消息队列相关 #################### |
| 5 | 4 | |
| ... | ... | @@ -26,16 +25,23 @@ yudao: |
| 26 | 25 | # 针对引入的 HTTP 组件的配置 |
| 27 | 26 | # ==================================== |
| 28 | 27 | http: |
| 28 | + enabled: true | |
| 29 | 29 | server-port: 8092 |
| 30 | 30 | # ==================================== |
| 31 | 31 | # 针对引入的 EMQX 组件的配置 |
| 32 | 32 | # ==================================== |
| 33 | 33 | emqx: |
| 34 | + enabled: true | |
| 35 | + http-auth-port: 8090 # MQTT HTTP 认证服务端口 | |
| 34 | 36 | mqtt-host: 127.0.0.1 # MQTT Broker 地址 |
| 35 | 37 | mqtt-port: 1883 # MQTT Broker 端口 |
| 36 | 38 | mqtt-username: admin # MQTT 用户名 |
| 37 | 39 | mqtt-password: public # MQTT 密码 |
| 38 | - auth-port: 8101 # 认证端口 | |
| 40 | + mqtt-ssl: false # 是否开启 SSL | |
| 41 | + mqtt-topics: | |
| 42 | + - "/sys/#" # 系统主题(设备上报) | |
| 43 | + - "/ota/#" # OTA 升级主题 | |
| 44 | + - "/config/#" # 配置主题 | |
| 39 | 45 | |
| 40 | 46 | # 消息总线配置 |
| 41 | 47 | message-bus: |
| ... | ... | @@ -50,4 +56,4 @@ logging: |
| 50 | 56 | cn.iocoder.yudao.module.iot.gateway.protocol.mqtt: DEBUG |
| 51 | 57 | cn.iocoder.yudao.module.iot.gateway.protocol.http: DEBUG |
| 52 | 58 | # MQTT 客户端日志 |
| 53 | - io.vertx.mqtt: DEBUG | |
| 54 | 59 | \ No newline at end of file |
| 60 | + io.vertx.mqtt: DEBUG | |
| 55 | 61 | \ No newline at end of file | ... | ... |