Commit f1368d9e792a2035720d3b38d94ed5a1b96d5ef1
1 parent
2737ffa1
reactor:【IoT 物联网】重构 MQTT 认证和事件处理逻辑,符合 EMQX 官方规范
Showing
3 changed files
with
129 additions
and
138 deletions
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/IotMqttUpstreamProtocol.java
| ... | ... | @@ -125,9 +125,8 @@ public class IotMqttUpstreamProtocol { |
| 125 | 125 | |
| 126 | 126 | // 创建认证处理器 |
| 127 | 127 | IotMqttHttpAuthHandler authHandler = new IotMqttHttpAuthHandler(this); |
| 128 | - router.post(IotMqttTopicUtils.MQTT_AUTH_AUTHENTICATE_PATH).handler(authHandler::authenticate); | |
| 129 | - router.post(IotMqttTopicUtils.MQTT_AUTH_CONNECTED_PATH).handler(authHandler::connected); | |
| 130 | - router.post(IotMqttTopicUtils.MQTT_AUTH_DISCONNECTED_PATH).handler(authHandler::disconnected); | |
| 128 | + router.post(IotMqttTopicUtils.MQTT_AUTH_PATH).handler(authHandler::handleAuth); | |
| 129 | + router.post(IotMqttTopicUtils.MQTT_EVENT_PATH).handler(authHandler::handleEvent); | |
| 131 | 130 | |
| 132 | 131 | // 启动 HTTP 服务器 |
| 133 | 132 | int authPort = emqxProperties.getHttpAuthPort(); |
| ... | ... | @@ -338,8 +337,8 @@ public class IotMqttUpstreamProtocol { |
| 338 | 337 | int qos = emqxProperties.getMqttQos(); |
| 339 | 338 | log.info("[subscribeToTopics][开始订阅主题, 共 {} 个, QoS: {}]", topicList.size(), qos); |
| 340 | 339 | |
| 341 | - int[] successCount = {0}; // 使用数组以便在 lambda 中修改 | |
| 342 | - int[] failCount = {0}; | |
| 340 | + int[] successCount = { 0 }; // 使用数组以便在 lambda 中修改 | |
| 341 | + int[] failCount = { 0 }; | |
| 343 | 342 | |
| 344 | 343 | for (String topic : topicList) { |
| 345 | 344 | mqttClient.subscribe(topic, qos, subscribeResult -> { | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/IotMqttHttpAuthHandler.java
| ... | ... | @@ -27,29 +27,34 @@ import static cn.iocoder.yudao.module.iot.gateway.enums.ErrorCodeConstants.DEVIC |
| 27 | 27 | public class IotMqttHttpAuthHandler { |
| 28 | 28 | |
| 29 | 29 | /** |
| 30 | - * 认证成功状态码 | |
| 30 | + * HTTP 成功状态码(EMQX 要求固定使用 200) | |
| 31 | 31 | */ |
| 32 | 32 | private static final int SUCCESS_STATUS_CODE = 200; |
| 33 | 33 | |
| 34 | 34 | /** |
| 35 | - * 参数错误状态码 | |
| 35 | + * 认证允许结果 | |
| 36 | 36 | */ |
| 37 | - private static final int BAD_REQUEST_STATUS_CODE = 400; | |
| 37 | + private static final String RESULT_ALLOW = "allow"; | |
| 38 | 38 | |
| 39 | 39 | /** |
| 40 | - * 认证失败状态码 | |
| 40 | + * 认证拒绝结果 | |
| 41 | 41 | */ |
| 42 | - private static final int UNAUTHORIZED_STATUS_CODE = 401; | |
| 42 | + private static final String RESULT_DENY = "deny"; | |
| 43 | 43 | |
| 44 | 44 | /** |
| 45 | - * 服务器错误状态码 | |
| 45 | + * 认证忽略结果 | |
| 46 | 46 | */ |
| 47 | - private static final int INTERNAL_ERROR_STATUS_CODE = 500; | |
| 47 | + private static final String RESULT_IGNORE = "ignore"; | |
| 48 | 48 | |
| 49 | 49 | /** |
| 50 | - * MQTT 协议实例,用于获取服务器ID | |
| 50 | + * EMQX 事件类型常量 | |
| 51 | 51 | */ |
| 52 | + private static final String EVENT_CLIENT_CONNECTED = "client.connected"; | |
| 53 | + private static final String EVENT_CLIENT_DISCONNECTED = "client.disconnected"; | |
| 54 | + | |
| 52 | 55 | private final IotMqttUpstreamProtocol protocol; |
| 56 | + private final IotDeviceMessageService deviceMessageService; | |
| 57 | + private final IotDeviceCommonApi deviceApi; | |
| 53 | 58 | |
| 54 | 59 | /** |
| 55 | 60 | * 构造器 |
| ... | ... | @@ -58,12 +63,14 @@ public class IotMqttHttpAuthHandler { |
| 58 | 63 | */ |
| 59 | 64 | public IotMqttHttpAuthHandler(IotMqttUpstreamProtocol protocol) { |
| 60 | 65 | this.protocol = protocol; |
| 66 | + this.deviceMessageService = SpringUtil.getBean(IotDeviceMessageService.class); | |
| 67 | + this.deviceApi = SpringUtil.getBean(IotDeviceCommonApi.class); | |
| 61 | 68 | } |
| 62 | 69 | |
| 63 | 70 | /** |
| 64 | 71 | * EMQX 认证接口 |
| 65 | 72 | */ |
| 66 | - public void authenticate(RoutingContext context) { | |
| 73 | + public void handleAuth(RoutingContext context) { | |
| 67 | 74 | try { |
| 68 | 75 | // 解析请求体 |
| 69 | 76 | JsonObject body = parseRequestBody(context); |
| ... | ... | @@ -71,35 +78,41 @@ public class IotMqttHttpAuthHandler { |
| 71 | 78 | return; |
| 72 | 79 | } |
| 73 | 80 | |
| 74 | - String clientid = body.getString("clientid"); | |
| 81 | + String clientId = body.getString("clientid"); | |
| 75 | 82 | String username = body.getString("username"); |
| 76 | 83 | String password = body.getString("password"); |
| 77 | 84 | |
| 78 | - log.debug("[authenticate][EMQX 设备认证, clientId: {}, username: {}]", clientid, username); | |
| 85 | + log.debug("[handleAuth][设备认证请求: clientId={}, username={}]", clientId, username); | |
| 79 | 86 | |
| 80 | 87 | // 参数校验 |
| 81 | - if (!validateAuthParams(context, clientid, username, password)) { | |
| 88 | + if (StrUtil.hasEmpty(clientId, username, password)) { | |
| 89 | + log.info("[handleAuth][认证参数不完整: clientId={}, username={}]", clientId, username); | |
| 90 | + sendAuthResponse(context, RESULT_DENY, false, "认证参数不完整"); | |
| 82 | 91 | return; |
| 83 | 92 | } |
| 84 | 93 | |
| 85 | 94 | // 执行设备认证 |
| 86 | - if (!performDeviceAuth(context, clientid, username, password)) { | |
| 87 | - return; | |
| 95 | + boolean authResult = performDeviceAuth(clientId, username, password); | |
| 96 | + if (authResult) { | |
| 97 | + log.info("[handleAuth][设备认证成功: {}]", username); | |
| 98 | + sendAuthResponse(context, RESULT_ALLOW, false, null); | |
| 99 | + } else { | |
| 100 | + log.info("[handleAuth][设备认证失败: {}]", username); | |
| 101 | + sendAuthResponse(context, RESULT_DENY, false, DEVICE_AUTH_FAIL.getMsg()); | |
| 88 | 102 | } |
| 89 | 103 | |
| 90 | - log.debug("[authenticate][设备认证成功, clientId: {}, username: {}]", clientid, username); | |
| 91 | - sendSuccessResponse(context, "认证成功"); | |
| 92 | - | |
| 93 | 104 | } catch (Exception e) { |
| 94 | - log.error("[authenticate][设备认证异常, 详细信息: {}]", e.getMessage(), e); | |
| 95 | - sendErrorResponse(context, INTERNAL_ERROR_STATUS_CODE, "认证服务异常"); | |
| 105 | + log.error("[handleAuth][设备认证异常]", e); | |
| 106 | + sendAuthResponse(context, RESULT_IGNORE, false, "认证服务异常"); | |
| 96 | 107 | } |
| 97 | 108 | } |
| 98 | 109 | |
| 99 | 110 | /** |
| 100 | - * EMQX 客户端连接事件钩子 | |
| 111 | + * EMQX 统一事件处理接口 | |
| 112 | + * 根据 EMQX 官方 Webhook 设计,统一处理所有客户端事件 | |
| 113 | + * 支持的事件类型:client.connected、client.disconnected 等 | |
| 101 | 114 | */ |
| 102 | - public void connected(RoutingContext context) { | |
| 115 | + public void handleEvent(RoutingContext context) { | |
| 103 | 116 | try { |
| 104 | 117 | // 解析请求体 |
| 105 | 118 | JsonObject body = parseRequestBody(context); |
| ... | ... | @@ -107,48 +120,52 @@ public class IotMqttHttpAuthHandler { |
| 107 | 120 | return; |
| 108 | 121 | } |
| 109 | 122 | |
| 110 | - String clientid = body.getString("clientid"); | |
| 123 | + String event = body.getString("event"); | |
| 111 | 124 | String username = body.getString("username"); |
| 112 | - Long timestamp = body.getLong("timestamp"); | |
| 113 | 125 | |
| 114 | - log.debug("[connected][设备连接, clientId: {}, username: {}, timestamp: {}]", | |
| 115 | - clientid, username, timestamp); | |
| 126 | + log.debug("[handleEvent][收到事件: {} - {}]", event, username); | |
| 127 | + | |
| 128 | + // 根据事件类型进行分发处理 | |
| 129 | + switch (event) { | |
| 130 | + case EVENT_CLIENT_CONNECTED: | |
| 131 | + handleClientConnected(body); | |
| 132 | + break; | |
| 133 | + case EVENT_CLIENT_DISCONNECTED: | |
| 134 | + handleClientDisconnected(body); | |
| 135 | + break; | |
| 136 | + default: | |
| 137 | + log.debug("[handleEvent][忽略事件: {}]", event); | |
| 138 | + break; | |
| 139 | + } | |
| 116 | 140 | |
| 117 | - handleDeviceStateChange(username, true, "设备连接"); | |
| 118 | - sendSuccessResponse(context, "处理成功"); | |
| 141 | + // EMQX Webhook 只需要200状态码,无需响应体 | |
| 142 | + context.response().setStatusCode(SUCCESS_STATUS_CODE).end(); | |
| 119 | 143 | |
| 120 | 144 | } catch (Exception e) { |
| 121 | - log.error("[connected][处理设备连接事件失败, 详细信息: {}]", e.getMessage(), e); | |
| 122 | - sendErrorResponse(context, INTERNAL_ERROR_STATUS_CODE, "处理失败"); | |
| 145 | + log.error("[handleEvent][事件处理失败]", e); | |
| 146 | + // 即使处理失败,也返回200避免EMQX重试 | |
| 147 | + context.response().setStatusCode(SUCCESS_STATUS_CODE).end(); | |
| 123 | 148 | } |
| 124 | 149 | } |
| 125 | 150 | |
| 126 | 151 | /** |
| 127 | - * EMQX 客户端断开连接事件钩子 | |
| 152 | + * 处理客户端连接事件 | |
| 128 | 153 | */ |
| 129 | - public void disconnected(RoutingContext context) { | |
| 130 | - try { | |
| 131 | - // 解析请求体 | |
| 132 | - JsonObject body = parseRequestBody(context); | |
| 133 | - if (body == null) { | |
| 134 | - return; | |
| 135 | - } | |
| 136 | - | |
| 137 | - String clientid = body.getString("clientid"); | |
| 138 | - String username = body.getString("username"); | |
| 139 | - String reason = body.getString("reason"); | |
| 140 | - Long timestamp = body.getLong("timestamp"); | |
| 141 | - | |
| 142 | - log.debug("[disconnected][设备断开连接, clientId: {}, username: {}, reason: {}, timestamp: {}]", | |
| 143 | - clientid, username, reason, timestamp); | |
| 154 | + private void handleClientConnected(JsonObject body) { | |
| 155 | + String username = body.getString("username"); | |
| 156 | + log.info("[handleClientConnected][设备上线: {}]", username); | |
| 157 | + handleDeviceStateChange(username, true); | |
| 158 | + } | |
| 144 | 159 | |
| 145 | - handleDeviceStateChange(username, false, "设备断开连接,原因:" + reason); | |
| 146 | - sendSuccessResponse(context, "处理成功"); | |
| 160 | + /** | |
| 161 | + * 处理客户端断开连接事件 | |
| 162 | + */ | |
| 163 | + private void handleClientDisconnected(JsonObject body) { | |
| 164 | + String username = body.getString("username"); | |
| 165 | + String reason = body.getString("reason"); | |
| 147 | 166 | |
| 148 | - } catch (Exception e) { | |
| 149 | - log.error("[disconnected][处理设备断开连接事件失败, 详细信息: {}]", e.getMessage(), e); | |
| 150 | - sendErrorResponse(context, INTERNAL_ERROR_STATUS_CODE, "处理失败"); | |
| 151 | - } | |
| 167 | + log.info("[handleClientDisconnected][设备下线: {} ({})]", username, reason); | |
| 168 | + handleDeviceStateChange(username, false); | |
| 152 | 169 | } |
| 153 | 170 | |
| 154 | 171 | /** |
| ... | ... | @@ -161,142 +178,113 @@ public class IotMqttHttpAuthHandler { |
| 161 | 178 | try { |
| 162 | 179 | JsonObject body = context.body().asJsonObject(); |
| 163 | 180 | if (body == null) { |
| 164 | - log.warn("[parseRequestBody][请求体为空]"); | |
| 165 | - sendErrorResponse(context, BAD_REQUEST_STATUS_CODE, "请求体不能为空"); | |
| 181 | + log.info("[parseRequestBody][请求体为空]"); | |
| 182 | + sendAuthResponse(context, RESULT_IGNORE, false, "请求体不能为空"); | |
| 166 | 183 | return null; |
| 167 | 184 | } |
| 168 | 185 | return body; |
| 169 | 186 | } catch (Exception e) { |
| 170 | 187 | log.error("[parseRequestBody][解析请求体失败]", e); |
| 171 | - sendErrorResponse(context, BAD_REQUEST_STATUS_CODE, "请求体格式错误"); | |
| 188 | + sendAuthResponse(context, RESULT_IGNORE, false, "请求体格式错误"); | |
| 172 | 189 | return null; |
| 173 | 190 | } |
| 174 | 191 | } |
| 175 | 192 | |
| 176 | 193 | /** |
| 177 | - * 验证认证参数 | |
| 178 | - * | |
| 179 | - * @param context 路由上下文 | |
| 180 | - * @param clientid 客户端ID | |
| 181 | - * @param username 用户名 | |
| 182 | - * @param password 密码 | |
| 183 | - * @return 验证是否通过 | |
| 184 | - */ | |
| 185 | - private boolean validateAuthParams(RoutingContext context, String clientid, String username, String password) { | |
| 186 | - if (StrUtil.hasEmpty(clientid, username, password)) { | |
| 187 | - log.warn("[validateAuthParams][认证参数不完整, clientId: {}, username: {}, password: {}]", | |
| 188 | - clientid, username, StrUtil.isNotEmpty(password) ? "***" : "空"); | |
| 189 | - sendErrorResponse(context, BAD_REQUEST_STATUS_CODE, "认证参数不完整"); | |
| 190 | - return false; | |
| 191 | - } | |
| 192 | - return true; | |
| 193 | - } | |
| 194 | - | |
| 195 | - /** | |
| 196 | 194 | * 执行设备认证 |
| 197 | 195 | * |
| 198 | - * @param context 路由上下文 | |
| 199 | - * @param clientid 客户端ID | |
| 196 | + * @param clientId 客户端ID | |
| 200 | 197 | * @param username 用户名 |
| 201 | 198 | * @param password 密码 |
| 202 | 199 | * @return 认证是否成功 |
| 203 | 200 | */ |
| 204 | - private boolean performDeviceAuth(RoutingContext context, String clientid, String username, String password) { | |
| 201 | + private boolean performDeviceAuth(String clientId, String username, String password) { | |
| 205 | 202 | try { |
| 206 | - IotDeviceCommonApi deviceApi = SpringUtil.getBean(IotDeviceCommonApi.class); | |
| 207 | 203 | CommonResult<Boolean> result = deviceApi.authDevice(new IotDeviceAuthReqDTO() |
| 208 | - .setClientId(clientid) | |
| 204 | + .setClientId(clientId) | |
| 209 | 205 | .setUsername(username) |
| 210 | 206 | .setPassword(password)); |
| 211 | 207 | |
| 212 | 208 | result.checkError(); |
| 213 | - if (!BooleanUtil.isTrue(result.getData())) { | |
| 214 | - log.warn("[performDeviceAuth][设备认证失败, clientId: {}, username: {}]", clientid, username); | |
| 215 | - sendErrorResponse(context, UNAUTHORIZED_STATUS_CODE, DEVICE_AUTH_FAIL.getMsg()); | |
| 216 | - return false; | |
| 217 | - } | |
| 218 | - return true; | |
| 209 | + return BooleanUtil.isTrue(result.getData()); | |
| 219 | 210 | } catch (Exception e) { |
| 220 | - log.error("[performDeviceAuth][设备认证异常, clientId: {}, username: {}]", clientid, username, e); | |
| 221 | - sendErrorResponse(context, INTERNAL_ERROR_STATUS_CODE, "认证服务异常"); | |
| 222 | - return false; | |
| 211 | + log.error("[performDeviceAuth][认证接口调用失败: {}]", username, e); | |
| 212 | + throw e; | |
| 223 | 213 | } |
| 224 | 214 | } |
| 225 | 215 | |
| 226 | 216 | /** |
| 227 | 217 | * 处理设备状态变化 |
| 228 | 218 | * |
| 229 | - * @param username 用户名 | |
| 230 | - * @param online 是否在线 | |
| 231 | - * @param actionDesc 操作描述 | |
| 219 | + * @param username 用户名 | |
| 220 | + * @param online 是否在线 | |
| 232 | 221 | */ |
| 233 | - private void handleDeviceStateChange(String username, boolean online, String actionDesc) { | |
| 222 | + private void handleDeviceStateChange(String username, boolean online) { | |
| 234 | 223 | if (StrUtil.isEmpty(username) || "undefined".equals(username)) { |
| 235 | - log.warn("[handleDeviceStateChange][用户名为空或'undefined', username: {}, action: {}]", | |
| 236 | - username, actionDesc); | |
| 237 | 224 | return; |
| 238 | 225 | } |
| 239 | 226 | |
| 240 | 227 | // 解析设备信息 |
| 241 | 228 | IotDeviceAuthUtils.DeviceInfo deviceInfo = IotDeviceAuthUtils.parseUsername(username); |
| 242 | 229 | if (deviceInfo == null) { |
| 243 | - log.warn("[handleDeviceStateChange][无法从 username({}) 解析设备信息, action: {}]", | |
| 244 | - username, actionDesc); | |
| 230 | + log.debug("[handleDeviceStateChange][跳过非设备连接: {}]", username); | |
| 245 | 231 | return; |
| 246 | 232 | } |
| 247 | 233 | |
| 248 | 234 | try { |
| 249 | - // 从协议实例获取服务器 ID | |
| 250 | 235 | String serverId = protocol.getServerId(); |
| 251 | 236 | if (StrUtil.isEmpty(serverId)) { |
| 252 | - log.error("[handleDeviceStateChange][获取服务器ID失败, username: {}, action: {}]", | |
| 253 | - username, actionDesc); | |
| 237 | + log.error("[handleDeviceStateChange][获取服务器ID失败]"); | |
| 254 | 238 | return; |
| 255 | 239 | } |
| 256 | 240 | |
| 257 | 241 | // 构建设备状态消息 |
| 258 | - IotDeviceMessageService deviceMessageService = SpringUtil.getBean(IotDeviceMessageService.class); | |
| 259 | - IotDeviceMessage message; | |
| 260 | - if (online) { | |
| 261 | - message = IotDeviceMessage.buildStateOnline(); | |
| 262 | - log.debug("[handleDeviceStateChange][发送设备上线消息, username: {}, serverId: {}]", | |
| 263 | - username, serverId); | |
| 264 | - } else { | |
| 265 | - message = IotDeviceMessage.buildStateOffline(); | |
| 266 | - log.debug("[handleDeviceStateChange][发送设备下线消息, username: {}, serverId: {}]", | |
| 267 | - username, serverId); | |
| 268 | - } | |
| 242 | + IotDeviceMessage message = online ? IotDeviceMessage.buildStateOnline() | |
| 243 | + : IotDeviceMessage.buildStateOffline(); | |
| 269 | 244 | |
| 270 | 245 | // 发送消息到消息总线 |
| 271 | 246 | deviceMessageService.sendDeviceMessage(message, |
| 272 | 247 | deviceInfo.getProductKey(), deviceInfo.getDeviceName(), serverId); |
| 273 | 248 | |
| 274 | - log.info("[handleDeviceStateChange][{}处理成功, productKey: {}, deviceName: {}, serverId: {}]", | |
| 275 | - actionDesc, deviceInfo.getProductKey(), deviceInfo.getDeviceName(), serverId); | |
| 249 | + log.info("[handleDeviceStateChange][设备状态更新: {}/{} -> {}]", | |
| 250 | + deviceInfo.getProductKey(), deviceInfo.getDeviceName(), | |
| 251 | + online ? "在线" : "离线"); | |
| 276 | 252 | |
| 277 | 253 | } catch (Exception e) { |
| 278 | - log.error("[handleDeviceStateChange][发送设备状态消息失败, username: {}, online: {}, action: {}]", | |
| 279 | - username, online, actionDesc, e); | |
| 254 | + log.error("[handleDeviceStateChange][发送设备状态消息失败: {}]", username, e); | |
| 280 | 255 | } |
| 281 | 256 | } |
| 282 | 257 | |
| 283 | 258 | /** |
| 284 | - * 发送成功响应 | |
| 259 | + * 发送 EMQX 认证响应 | |
| 260 | + * 根据 EMQX 官方文档要求,必须返回 JSON 格式响应 | |
| 261 | + * | |
| 262 | + * @param context 路由上下文 | |
| 263 | + * @param result 认证结果:allow、deny、ignore | |
| 264 | + * @param isSuperuser 是否超级用户 | |
| 265 | + * @param message 日志消息(仅用于日志记录,不返回给EMQX) | |
| 285 | 266 | */ |
| 286 | - private void sendSuccessResponse(RoutingContext context, String message) { | |
| 267 | + private void sendAuthResponse(RoutingContext context, String result, boolean isSuperuser, String message) { | |
| 268 | + // 构建符合 EMQX 官方规范的响应 | |
| 269 | + JsonObject response = new JsonObject() | |
| 270 | + .put("result", result) | |
| 271 | + .put("is_superuser", isSuperuser); | |
| 272 | + | |
| 273 | + // 可以根据业务需求添加客户端属性 | |
| 274 | + // response.put("client_attrs", new JsonObject().put("role", "device")); | |
| 275 | + | |
| 276 | + // 可以添加认证过期时间(可选) | |
| 277 | + // response.put("expire_at", System.currentTimeMillis() / 1000 + 3600); | |
| 278 | + | |
| 279 | + // 记录详细的响应日志(message仅用于日志,不返回给EMQX) | |
| 280 | + if (StrUtil.isNotEmpty(message)) { | |
| 281 | + log.debug("[sendAuthResponse][响应详情: result={}, message={}]", result, message); | |
| 282 | + } | |
| 283 | + | |
| 287 | 284 | context.response() |
| 288 | 285 | .setStatusCode(SUCCESS_STATUS_CODE) |
| 289 | - .putHeader("Content-Type", "text/plain; charset=utf-8") | |
| 290 | - .end(message); | |
| 286 | + .putHeader("Content-Type", "application/json; charset=utf-8") | |
| 287 | + .end(response.encode()); | |
| 291 | 288 | } |
| 292 | 289 | |
| 293 | - /** | |
| 294 | - * 发送错误响应 | |
| 295 | - */ | |
| 296 | - private void sendErrorResponse(RoutingContext context, int statusCode, String message) { | |
| 297 | - context.response() | |
| 298 | - .setStatusCode(statusCode) | |
| 299 | - .putHeader("Content-Type", "text/plain; charset=utf-8") | |
| 300 | - .end(message); | |
| 301 | - } | |
| 302 | 290 | } |
| 303 | 291 | \ No newline at end of file | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java
| ... | ... | @@ -21,22 +21,26 @@ public final class IotMqttTopicUtils { |
| 21 | 21 | */ |
| 22 | 22 | private static final String SERVICE_TOPIC_PREFIX = "/thing/"; |
| 23 | 23 | |
| 24 | - // ========== MQTT 认证路径常量 ========== | |
| 24 | + // ========== MQTT HTTP 接口路径常量 ========== | |
| 25 | 25 | |
| 26 | 26 | /** |
| 27 | - * MQTT 认证路径 | |
| 27 | + * MQTT 认证接口路径 | |
| 28 | + * 对应 EMQX HTTP 认证插件的认证请求接口 | |
| 28 | 29 | */ |
| 29 | - public static final String MQTT_AUTH_AUTHENTICATE_PATH = "/mqtt/auth/authenticate"; | |
| 30 | + public static final String MQTT_AUTH_PATH = "/mqtt/auth"; | |
| 30 | 31 | |
| 31 | 32 | /** |
| 32 | - * MQTT 连接事件路径 | |
| 33 | + * MQTT 统一事件处理接口路径 | |
| 34 | + * 对应 EMQX Webhook 的统一事件处理接口,支持所有客户端事件 | |
| 35 | + * 包括:client.connected、client.disconnected、message.publish 等 | |
| 33 | 36 | */ |
| 34 | - public static final String MQTT_AUTH_CONNECTED_PATH = "/mqtt/auth/connected"; | |
| 37 | + public static final String MQTT_EVENT_PATH = "/mqtt/event"; | |
| 35 | 38 | |
| 36 | 39 | /** |
| 37 | - * MQTT 断开事件路径 | |
| 40 | + * MQTT 授权接口路径(预留) | |
| 41 | + * 对应 EMQX HTTP 授权插件的授权检查接口 | |
| 38 | 42 | */ |
| 39 | - public static final String MQTT_AUTH_DISCONNECTED_PATH = "/mqtt/auth/disconnected"; | |
| 43 | + public static final String MQTT_AUTHZ_PATH = "/mqtt/authz"; | |
| 40 | 44 | |
| 41 | 45 | // ========== 工具方法 ========== |
| 42 | 46 | ... | ... |