RabbitMQ使用MQTT

Mosquitto虽然安装与使用都很容易,但缺少原生的用户访问控制,而其用户管理插件mosquitto-auth-plug也于2019年停止更新。

RabbitMQ自带插件支持MQTT,可通过HTTP API进行用户管理。本文介绍如何为将RabbitMQ配置为MQTT消息中间件。

安装RabbitMQ

根据操作系统选择安装方式,若使用Arch Linux:

yay -S --needed --noconfirm  rabbitmq
sudo systemctl enable --now rabbitmq.service

启用插件

# 启用MQTT插件
sudo rabbitmq-plugins enable rabbitmq_mqtt
# 若需要在浏览器里使用MQTT还需要启用MQTT over Websocket支持
rabbitmq-plugins enable rabbitmq_web_mqtt

# Web控制台页面,建议启用
sudo rabbitmq-plugins enable rabbitmq_management

配置

使用Web控制台

启用rabbitmq_management插件后,可通过浏览器访问http://localhost:15672配置RabbitMQ。默认用户名与密码为guest

使用命令行新建用户并配置权限

# 创建用户`mqtt-test`, 密码为`mqtt-password`:
rabbitmqctl add_user mqtt-test mqtt-password
# 配置权限: rabbitmqctl set_permissions -p [virtal host] [user] [config-regexp] [write-regexp] [read-regexp]
rabbitmqctl set_permissions -p / mqtt-test ".*" ".*" ".*"
# 为用户设置management标签
rabbitmqctl set_user_tags mqtt-test management

通过HTTP API管理用户

所有HTTP API都需要使用Basic Authentication授权。详细文档可在安装RabbitMQ后访问http://localhost:15672/api/index.html查看。

# 添加用户,如果用户已经存在则会覆盖
curl -v -u guest:guest  -X PUT -d '{"password": "test", "tags": "test"}'  http://localhost:15672/api/users/test
# 获取所有用户列表
curl -u guest:guest http://localhost:15672/api/users |jq
# 添加Virtual host
curl -u guest:guest -X PUT http://localhost:15672/api/vhosts/test
# 获取用户权限列表
curl -u guest:guest http://localhost:15672/api/users/test/permissions |jq

配置MQTT

使用默认配置时,在本机(localhost)可以匿名使用MQTT队列。此时RabbitMQ实际使用的是guest用户访问消息队列。

注意事项:

  • MQTT用户必须对MQTT使用的Virtual Host(默认为/)具有完整权限(即config/write/read权限均为".*")。
  • 不要在队列名里使用/.这两个字符;RabbitMQ对包含这两个字符的队列名支持并不好。

下面调用HTTP API创建名为test的用户,这个用户对msg-test-d2s队列有写权限,对msg-test-s2d有读权限:

MQTT的Virtual Host及Exchange必须与配置文件配置一致。

# 新建用户
curl -v -u guest:guest  -X PUT -d '{"password": "test", "tags": "test"}'  http://localhost:15672/api/users/test
# 配置Virtual Host权限,注意URL里包含特殊字符时需要编码, `%2F` 是URL-encoding的结果
curl -v -u guest:guest  -X PUT -d '{"username":"test","vhost":"/","configure":".*","write":".*","read":".*"}'  http://localhost:15672/api/permissions/%2F/test
# 设置此用户的MQTT访问权限,再次调用时会替换上次的配置
curl -v -u guest:guest  -X PUT -d '{"username":"test","vhost":"/","exchange":"amq.topic","write":"^msg-{username}-d2s$","read":"^msg-{username}-s2d$"}' \
 http://localhost:15672/api/topic-permissions/%2F/test
# 查看用户权限
curl -u guest:guest http://localhost:15672/api/topic-permissions/%2F/test |jq

同一用户对于同一Virtual Host及Exchange只能配置一项权限,所以用户对多个主题有读写权限时,只能通过正则表达式实现。

配置文件

通过配置文件可以配置是否启用匿名用户,配置匿名用户对应的实际对应的用户名,配置Websocket端口等。

修改/etc/rabbitmq/rabbitmq.conf

# 是否允许匿名用户
mqtt.allow_anonymous = true
# 允许匿名用户时,实际使用的用户与密码。注意此用户需要在RabbitMQ中存在。
mqtt.default_user = guest
mqtt.default_pass = guest
# MQTT使用的Virtual Host及exchange,必须与配置MQTT用户权限时一致
mqtt.vhost            = /
mqtt.exchange         = amq.topic
# millis, 24 小时
mqtt.subscription_ttl = 86400000
mqtt.prefetch         = 0
# 配置Websocket 端口
web_mqtt.tcp.port = 9001

测试MQTT

使用mosquitto_pubmosquitto_sub命令测试。

订阅消息:

mosquitto_sub  -h 127.0.0.1 -u test -P test   -t "msg-test-s2d"

新建一个命令行窗口发布消息,注意这里使用了匿名用户guest,匿名用户对所有topic有读写权限:

mosquitto_sub  -h 127.0.0.1  -t "msg-test-s2d" -m "msg-from-server"

此时在订阅端应该能收到消息。若没有收到需要检查

  • 用户名与密码是否正确。MQTT协议没有规定如何处理用户名/密码错误的场景,所以用户名或密码错误时可能收不到任何错误信息!
  • 对相应的MQTT队列是否有读权限。

参考

Comment