前言

欢迎来到 xxxzsh 的 MQTT 三部曲

这是一个围绕 MQTT 的系列文章,我会用三篇内容,带你完整走一遍 MQTT 在真实项目中的使用过程——从理解协议,到搭建服务,再到 Java 项目接入。

在上一篇里,我们已经把 MQTT 的基本概念、设计思路以及它适合解决什么问题讲清楚了。这一篇我们直接进入实战:
搭建一个 MQTT Broker,本篇会以 EMQX 作为示例,带大家完成:

  • MQTT 服务的启动

  • 管理控制台的使用

  • 客户端连接与账号配置

  • 基础的权限隔离思路

本文不会再重复 MQTT 的基础原理,因此更适合已经对 MQTT 有基本了解的同学阅读。
如果你想先系统了解 MQTT,可以先阅读第一篇:

👉 MQTT 是什么?一文读懂 MQTT 协议的原理与优势(点击跳转

一、MQTT ≠ 服务

学习了MQTT原理的小伙伴应该明白,但由于这个概念非常重要,所以我还是要重申一下。

在实际使用中,我们需要部署一个实现了 MQTT 协议的 消息服务器(Broker),客户端才能通过 MQTT 协议进行通信。

常见的 MQTT Broker 实现包括 Mosquitto、HiveMQ、EMQX 等。
本文选择 EMQX 作为 MQTT Broker,并通过 Docker 的方式进行部署。

后文中提到的“MQTT 服务”,均指 EMQX 提供的 MQTT Broker 能力,而非 MQTT 协议本身。

下面开始运行EMQX:

二、Docker运行EMQX

创建挂载目录

mkdir -p /opt/emqx/{data,log,etc}
chmod -R 777 /opt/emqx

docker 启动:

docker run -d \
--name emqx \
--restart unless-stopped \
-p 1883:1883 \
-p 8883:8883 \
-p 8083:8083 \
-p 8084:8084 \
-p 18083:18083 \
-v /opt/emqx/data:/opt/emqx/data \
-v /opt/emqx/log:/opt/emqx/log \
emqx/emqx:5.8.8

docker-compose 启动:

  emqx:
    image: emqx:5.8.8
    container_name: emqx
    restart: unless-stopped
    environment:
      - EMQX_NODE__NAME=emqx@127.0.0.1  # 固定节点名称
    ports:
      - "1883:1883"     # MQTT TCP
      - "8883:8883"     # MQTT SSL
      - "8083:8083"     # MQTT over WebSocket
      - "8084:8084"     # MQTT over WSS
      - "18083:18083"   # EMQX Dashboard

    volumes:
      - /opt/emqx/data:/opt/emqx/data
      - /opt/emqx/log:/opt/emqx/log

端口说明

端口作用
1883MQTT TCP(重点)
8883MQTT SSL
8083MQTT over WS
8084MQTT over WSS
18083管理后台(重点)

最主要的就是这个1883了,未来最基本的TCP连接就是用这个1883。

看看日志:

docker logs -f emqx

这样就是OK了。


三、使用EMQX管理控制台

浏览器访问

你的IP:18083

账号密码默认是 admin \ public

第一次登录后要改密,记得保存。

后续我们就要通过这个控制台,去配置EMQX的客户端连接、ACL等。

四、使用 MQTT 客户端工具验证 EMQX 服务

前面我们已经通过 Docker 成功部署了 EMQX(MQTT Broker)
接下来,在正式开发客户端之前,通常需要先验证 Broker 是否能够正常连接和收发消息。

类似于:

  • MySQL 常用 Navicat

  • Redis 常用 Redis Desktop Manager(RDM)

4.1 常见的 MQTT 客户端工具

目前常用的 MQTT 客户端工具包括:

  • MQTTX

  • MQTT Explorer

  • mosquitto_pub / mosquitto_sub(命令行)

感觉各有各的好处吧。本文以 MQTTX 为例进行演示。官网地址:

MQTTX:全功能 MQTT 客户端工具https://mqttx.app/zh你可以用在线的,也可以下载个桌面版。(MQTTX和EMQX是一家公司做的,所以你会发现整体UI风格很像):

4.2 客户端工具连接

打开MQTTX,新建连接:

Client ID 得是全局唯一的。

账号密码不用填,因为现在是默认开放状态。尝试一下连接,并复制一个连接:

连接之后,我们可以新建一个监听:

然后我们现在来模拟一下收发。开两个窗口:

到这里就是OK了。你已经成功搭建好了EMQX(MQTT Broker)。如果是基本的学习等,现在我们已经可以开始用了。比如接入你的Java项目、大数据平台等等。

五、客户端认证

上面我们已经搭建好了 EMQX,但实际使用中,我们肯定是配置访问账号密码,不可能公网暴漏出去给别人随便访问。

我们现在就来创建一下账号密码。

EMQX提供了非常方便的创建认证方式,打开管理控制台。

5.1 创建数据源

左侧 访问控制 -> 客户端认证 -> 点击右上角的创建。

可以看到它有很多选择,内置数据库、MySQL、MongoDB等常用数据源都可以。我们就用内置数据库就好,参数配置默认。

注意:

一旦启用了认证方式,EMQX 会默认拒绝所有匿名连接,只有通过认证的客户端才允许建立连接。所以如果你的MQTT正在被一些项目使用,请注意项目情况。

这个时候你再去客户端工具连接你就发现连不上了:

5.2 新建用户

我创建了一个账号test,密码testtest的用户:

打开连接工具,输入账号密码就发现可以连接了:

六、客户端授权(权限隔离)

在上一节中,我们已经通过 客户端认证 实现了「只有知道账号密码的客户端才能连接 EMQX」。

但在生产中这还远远不够。

6.1 为什么需要客户端授权(ACL)

我们先举一个非常典型的业务场景:

  • 系统中有很多设备

  • 每个设备都有自己的 Topic:

  • device/{deviceId}/up
    device/{deviceId}/down

  • 不同客户端的权限应该不同:

    • 普通用户:只能操作自己的设备

    • 管理端:可以查看所有设备

    • 第三方系统:只读,不能发指令

如果没有权限隔离,会发生什么?

  • 任意客户端都能:

    • 订阅所有设备数据

    • 向任意设备下发指令

  • 一旦账号泄露,后果不可控

因此,客户端授权(ACL)是 MQTT 系统中非常核心的一环


6.2 什么是 ACL(Access Control List)

ACL,全称 Access Control List(访问控制列表)

在 MQTT 中,ACL 本质上解决的是一个问题:

谁(客户端)

能不能

对某个 Topic

进行发布(publish)或订阅(subscribe)

可以简单理解为一个三元组:

Client  +  Action  +  Topic

其中:

  • Client:客户端身份(username / clientId 等)

  • Action:

    • publish(发布)

    • subscribe(订阅)

  • Topic:MQTT 的主题路径


6.3 ACL 规则基本语法(不需要记)

EMQX 中,File 的一条 ACL 规则的基本格式如下:

allow | deny who action topic

拆解说明:

部分含义
allow / deny允许 / 拒绝
whousername / clientid / all
actionpublish / subscribe / pubsub
topic具体的 Topic(支持通配符)

打开 EMQX 控制台,打开左侧 访问控制 -> 客户端授权 ,可以看到默认的时候,就能看到EMQX已经配置了一个File了:

打开可以看到:

按上面的语法依次解释就是:

  1. 允许 EMQX 管理后台(dashboard 用户)订阅系统监控 Topic
  2. 来自本机的客户端,对所有 Topic 可随便收、随便发
  3. 禁止任何客户端通过通配符一次性订阅整个 MQTT 系统
  4. 如果前面都没匹配到,那就默认允许一切行为

看到3,这个就是我们不能订阅 # 来监听全部topic的原因:

我们注释掉,更新,再去连接就会发现可以订阅 # 了。

再举几个简单的例子:

允许所有客户端订阅所有设备的上报 Topic:

allow all subscribe device/+/up

禁止任何客户端向任何 Topic 发布消息:

deny all publish #

6.4 EMQX 内置数据库配置ACL

和客户端认证一样,除了文件,我们还可以配置其它数据源。

同样打开 EMQX 控制台中的客户端授权,点击右上角的创建,​​本文后续的演示中我们还是使用内置数据库,如下:

注意!

多个数据源存在的话,它就是匹配多个规则,哪个能匹配上就哪个。比如说,

  • 全局的File里面我们配了禁止 # 订阅全部
  • 在内置数据源里面配置了 zhangsan 这个号可以订阅 #

那么,zhangsan也可以订阅成功 # 。

6.5 示例场景

下面我们通过一个非常贴近真实业务的例子,来演示 ACL 的配置方式。

假设我们有两个用户:

用户一:张三(username = zhangsan)

  • 只允许:

    • 向自己设备 S001 上报数据

    • 接收自己设备的消息

  • 不能访问任何其它设备

设备 Topic 设计如下:

device/S001/up

device/S001/down

内置数据库的配置就方便的多了,EMQX已经给我们封装好了。如下就是配置了zhangsan这个用户的:


用户二:李四(username = lisi)

  • 只允许:

    • 接收所有设备的上报数据

  • 不允许:

    • 向任何 Topic 发布消息

    6.6 在 EMQX 里,ACL 能做到什么程度?

    限制 publish / subscribe
    精确 Topic
    通配符(+ / #)
    基于 username
    基于 clientId
    基于 IP
    动态规则
    数据库 / HTTP / JWT

    它支持动态占位符。比如 ${username} clientId之类的。

    6.7 优化Topic设计

    从上面的 6.5 我们了解到了每个用户都可以配置自己的ACL,但这时你会发现这样一个个 

    device/设备ID/up(down)

    之类的配置过去,非常麻烦,总不能以后加一个设备来编辑一次吧。

    所以我们可以试着优化一下MQTT的Topic的设计。

    首先,我们明确一下需求:

    1,除了用户自己用户名下的topic,其它topic都不能发布和订阅

    2,配置完后续不需要任何的改动

    第一点我们直接配置一个所有用户拒绝 # 就好了。

    第二点我们则需要设计一下。

    我给两个方案:

    方案一

    我们可以把设备上报的Topic改成:

    device/所属用户/up

    举个例子,zhangsan的两台设备S001和S002原先是上报到

    device/S001/up

    device/S002/up

    那么我们都统一到:

    device/zhangsan/up

    然后在上报的数据中,去定义比如

    {
        "id": "S001",
        "status": "active"

    ...
    }

    这样后续不管来多少设备,都是往用户的固定的topic发,就不需要每次来都配置ACL了。

    这样我们的EMQX中,就可以配置一个全局规则(所有用户):

    device/${username}/up

    需要注意的是,拒绝 # 一定是要在最底下,不然连接会直接被拒绝。

    方案二

    其实也类似,也是先用username包一层,只不过后面跟着设备ID区分。

    还是以zhangsan的两台设备S001和S002的两台为例:

    device/zhangsan/S001/up

    device/zhangsan/S002/up

    ...

    然后在所有用户配置中就可以用

    device/${username}/#

    或者

    device/${username}/+/up

    设计起来反正都大差不差。我这里就抛砖引玉一下,大家在实战中摸索两次就懂了。

    七、总结

    本文中,我们完成了从 EMQX 环境搭建生产级权限管控 的全过程:

    1. 快速部署:利用 Docker 的便捷性,我们几分钟内就搭建起了一个高性能的 MQTT Broker。

    2. 安全加固:通过“客户端认证”,确保只有合法用户能进入系统。

    3. 精细化管理:通过“ACL 授权”,我们实现了业务上的权限隔离,彻底解决了设备间数据误发、越权监听的安全隐患。

    4. 架构优化:在最后的 Topic 设计优化中,我们看到了如何利用 动态占位符 实现“一劳永逸”的权限规则配置。

    其实关键就在于对安全和规范的把控。MQTT 协议虽然简洁,但配合 EMQX 强大的认证授权机制,才能真正支撑起海量设备的安全通信。

    希望这篇文章能帮你打通 MQTT 学习思路。

    Logo

    智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

    更多推荐