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
- 使用QoS 1消息时,可能需要修改
mqtt.subscription_ttl
,参考Session Stickiness (Clean and Non-clean Sessions) and Queue/Subscription TTL mqtt.prefetch
配置无应答消息的最大发送数量,0表示无限制。
测试MQTT
使用mosquitto_pub
与mosquitto_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队列是否有读权限。