概述
比官网详细,EMQ X MQTT 发布订阅 ACL 权限教程指南,包括 MySQL ACL、Redis ACL、MongoDB ACL、以及 HTTP 认证全部插件。
EMQ X 支持通过客户端发布订阅 ACL 进行客户端权限的管理,本文介绍了 EMQ X 支持的发布订阅 ACL 以及对应插件的MQTT 发布订阅权限配置管理的方法。
EMQ X MQTT Broker 简介
EMQ X Broker 是基于高并发的 Erlang/OTP 语言平台开发,支持百万级连接和分布式集群架构,发布订阅模式的开源 MQTT 消息服务器。
EMQ X Broker 在全球物联网市场广泛应用。无论是产品原型设计、物联网创业公司、还是大规模的商业部署,EMQ X Broker 都支持开源免费使用。
ACL 插件
EMQ X 支持使用配置文件、外部主流数据库和自定义 HTTP API 作为 ACL 数据源。
连接数据源、进行访问控制功能是通过插件实现的,使用前需要启用相应的插件。
客户端订阅主题、发布消息时插件通过检查目标主题(Topic)是否在指定数据源允许/禁止列表内来实现对客户端的发布、订阅权限管理。
配置文件
- 内置 ACL
使用配置文件提供认证数据源,适用于变动较小的 ACL 管理。
外部数据库
- MySQL ACL
- PostgreSQL ACL
- Redis ACL
- MongoDB ACL
外部数据库可以存储大量数据、动态管理 ACL,方便与外部设备管理系统集成。
其他
- HTTP ACL
HTTP ACL 能够实现复杂的 ACL 管理。
ACL 功能包含在认证鉴权插件中,更改插件配置后需要重启插件才能生效,
规则详解
ACL 是允许与拒绝条件的集合,EMQ X 中使用以下元素描述 ACL 规则:
[权限:允许|拒绝] [对象:IP 地址|用户名|Client ID] [动作:发布|订阅|发布订阅] [目标:主题] |
同时具有多条 ACL 规则时,EMQ X 将按照规则排序进行合并,以 ACL 文件 中的默认 ACL 为例,ACL 文件中配置了默认的 ACL 规则,规则从下至上加载:
- 第一条规则允许客户端发布订阅所有主题
- 第二条规则禁止全部客户端订阅
$SYS/#
与#
主题 - 第三条规则允许 ip 地址为
127.0.0.1
的客户端发布/订阅$SYS/#
与#
主题,为第二条开了特例 - 第四条规则允许用户名为
dashboard
的客户端订阅$SYS/#
主题,为第二条开了特例
{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}. |
授权结果
任何一次 ACL 授权最终都会返回一个结果:
- 允许:经过检查允许客户端进行操作
- 禁止:经过检查禁止客户端操作
- 忽略(ignore):未查找到 ACL 权限信息,无法显式判断结果是允许还是禁止,交由下一 ACL 插件或默认 ACL 规则来判断
全局配置
默认配置中 ACL 是开放授权的,即授权结果为忽略(ignore)时允许客户端通过授权。
通过 etc/emqx.conf
中的 ACL 配置可以更改该属性:
# etc/emqx.conf |
配置默认 ACL 文件,使用文件定义默认 ACL 规则:
# etc/emqx.conf |
配置 ACL 授权结果为禁止的响应动作,为 ignore
时将断开设备:
# etc/emqx.conf |
超级用户(superuser)
客户端可拥有“超级用户”身份,超级用户拥有最高权限不受 ACL 限制。
- 认证鉴权插件启用超级用户功能后,发布订阅时 EMQ X 将优先检查客户端超级用户身份
- 客户端为超级用户时,通过授权并跳过后续 ACL 检查
ACL 缓存
客户端发布、订阅频率较高的情况下开启 ACL 缓存可以提高 ACL 检查性能。
在 etc/emqx.conf
可以配置 ACL 缓存大小与缓存时间:
# etc/emqx.conf |
ACL 鉴权链
当同时启用多个 ACL 插件时,EMQ X 将按照插件开启先后顺序进行链式鉴权:
- 一通过授权,终止链并允许客户端通过验证
- 一旦授权失败,终止链并禁止客户端通过验证
- 直到最后一个 ACL 插件仍未通过,根据默认授权配置判定
- 默认授权为允许时,允许客户端通过验证
- 默认授权为禁止时,禁止客户端通过验证
同时只启用一个 ACL 插件可以提高客户端 ACL 检查性能。
内置 ACL
内置 ACL 通过文件设置规则,使用上足够简单轻量,适用于规则数量可预测、无变动需求或变动较小的项目。
ACL 规则文件:
etc/acl.conf |
内置 ACL 优先级最低,可以被 ACL 插件覆盖,如需禁用全部注释即可。规则文件更改后需重启 EMQ X 以应用生效。
定义 ACL
内置 ACL 使用 Erlang 语法进行规则定义,规则从下到上依次覆盖,定义方式为:
[权限:允许|拒绝] [对象:IP 地址|用户名|Client ID] [动作:发布|订阅|发布订阅] [目标:主题] |
你可以在主题中使用以下占位符,ACL 授权检查时 EMQ X 将自动填充为客户端信息:
- %u:用户名
- %c:Client ID
- %a:客户端 IP 地址
默认规则文件:etc/acl.conf
:
# etc/acl.conf |
EMQ X 启动时将读取 ACL 文件并将数据加载到内存中,节点上的 ACL 数据会在此阶段同步至集群。
修改改 ACL 文件后需要使用 ./bin/emqx_ctl acl reload
命令或重启 EMQ X 以更新规则。
MySQL ACL
MySQL ACL 使用外部 MySQL 数据库存储 ACL 规则,可以存储大量数据、动态管理 ACL,方便与外部设备管理系统集成
插件:
emqx_auth_mysql |
emqx_auth_mysql 插件同时包含认证功能,可通过注释禁用。
MySQL 连接信息
MySQL 基础连接信息,需要保证集群内所有节点均能访问。
# etc/plugins/emqx_auth_mysql.conf |
默认表结构
MySQL 认证插件默认配置下需要确保数据库中有以下两张数据表,用于存储认证规则信息:
认证/超级用户表
CREATE TABLE `mqtt_user` ( |
示例数据:
-- 客户端信息 |
ACL 规则表
CREATE TABLE `mqtt_acl` ( |
规则表字段说明:
- allow:禁止(0),允许(1)
- ipaddr:设置 IP 地址
- username:连接客户端的用户名,此处的值如果设置为
$all
表示该规则适用于所有的用户 - clientid:连接客户端的 Client ID
- access:允许的操作:订阅(1),发布(2),订阅发布都可以(3)
- topic:控制的主题,可以使用通配符,并且可以在主题中加入占位符来匹配客户端信息,例如
t/%c
则在匹配时主题将会替换为当前客户端的 Client ID- %u:用户名
- %c:Client ID
默认配置下示例数据:
-- 所有用户不可以订阅系统主题 |
启用 MySQL ACL 后并以用户名 emqx 成功连接后,客户端应当数据具有相应的主题权限。
这是默认配置使用的表结构,熟悉该插件的使用后你可以使用任何满足条件的数据表进行 ACL 规则存储。
超级用户 SQL(super_query)
进行 ACL 鉴权时,EMQ X 将使用当前客户端信息填充并执行用户配置的超级用户 SQL,查询客户端是否为超级用户。客户端为超级用户时将跳过 ACL SQL。
# etc/plugins/emqx_auth_mysql.conf |
你可以在 SQL 中使用以下占位符,执行时 EMQ X 将自动填充为客户端信息:
- %u:用户名
- %c:Client ID
- %C:TLS 证书公用名(证书的域名或子域名),仅当 TLS 连接时有效
- %d:TLS 证书 subject,仅当 TLS 连接时有效
你可以根据业务需要调整超级用户 SQL,如添加多个查询条件、使用数据库预处理函数,以实现更多业务相关的功能。但是任何情况下超级用户 SQL 需要满足以下条件:
- 查询结果中必须包含 is_superuser 字段,is_superuser 应该显式的为 true
- 查询结果只能有一条,多条结果时只取第一条作为有效数据
如果不需要超级用户功能,注释并禁用该选项能有效提高效率
ACL SQL(acl_query)
进行 ACL 鉴权时,EMQ X 将使用当前客户端信息填充并执行用户配置的超级用户 SQL,如果没有启用超级用户 SQL 或客户端不是超级用户,则使用 ACL SQL 查询出该客户端在数据库中的 ACL 规则。
# etc/plugins/emqx_auth_mysql.conf |
你可以在 ACL SQL 中使用以下占位符,执行时 EMQ X 将自动填充为客户端信息:
- %u:用户名
- %c:Client ID
- %C:TLS 证书公用名(证书的域名或子域名),仅当 TLS 连接时有效
- %d:TLS 证书 subject,仅当 TLS 连接时有效
你可以根据业务需要调整 ACL SQL,如添加多个查询条件、使用数据库预处理函数,以实现更多业务相关的功能。但是任何情况下 ACL SQL 需要满足以下条件:
- 查询结果中必须包含 allow、access、topic、clientid、username、ipaddr 字段,如果字段不想参与比对则使用
$all
字符串或者数据库NULL
值 - 查询结果可以有多条,多条结果时按照从上到下的顺序进行匹配
可以在 SQL 中调整查询条件、指定排序方式实现更高效率的查询。
特殊说明
MySQL 8.0 及以后版本使用了 caching_sha2_password
作为默认身份验证插件,受限于客户端驱动你必须将其更改为 mysql_native_password
插件:
ALTER USER 'your_username'@'your_host' IDENTIFIED WITH mysql_native_password BY 'your_password'; |
PostgreSQL ACL
PostgreSQL ACL 使用外部 PostgreSQL 数据库存储 ACL 规则,可以存储大量数据、动态管理 ACL,方便与外部设备管理系统集成。
插件:
emqx_auth_pgsql |
emqx_auth_pgsql 插件同时包含认证功能,可通过注释禁用。
PostgreSQL 连接信息
PostgreSQL 基础连接信息,需要保证集群内所有节点均能访问。
# etc/plugins/emqx_auth_pgsql.conf |
默认表结构
PostgreSQL 认证插件默认配置下需要确保数据库中有以下两张数据表,用于存储认证规则信息:
认证/超级用户表
CREATE TABLE mqtt_user ( |
示例数据:
-- 客户端信息 |
ACL 规则表
CREATE TABLE mqtt_acl ( |
规则表字段说明:
- allow:禁止(0),允许(1)
- ipaddr:设置 IP 地址
- username:连接客户端的用户名,此处的值如果设置为
$all
表示该规则适用于所有的用户 - clientid:连接客户端的 Client ID
- access:允许的操作:订阅(1),发布(2),订阅发布都可以(3)
- topic:控制的主题,可以使用通配符,并且可以在主题中加入占位符来匹配客户端信息,例如
t/%c
则在匹配时主题将会替换为当前客户端的 Client ID- %u:用户名
- %c:Client ID
默认配置下示例数据:
-- 所有用户不可以订阅系统主题 |
启用 PostgreSQL ACL 后并以用户名 emqx 成功连接后,客户端应当数据具有相应的主题权限。
这是默认配置使用的表结构,熟悉该插件的使用后你可以使用任何满足条件的数据表进行 ACL 规则存储。
超级用户 SQL(super_query)
进行 ACL 鉴权时,EMQ X 将使用当前客户端信息填充并执行用户配置的超级用户 SQL,查询客户端是否为超级用户。客户端为超级用户时将跳过 ACL SQL。
# etc/plugins/emqx_auth_pgsql.conf |
你可以在 SQL 中使用以下占位符,执行时 EMQ X 将自动填充为客户端信息:
- %u:用户名
- %c:Client ID
- %C:TLS 证书公用名(证书的域名或子域名),仅当 TLS 连接时有效
- %d:TLS 证书 subject,仅当 TLS 连接时有效
你可以根据业务需要调整超级用户 SQL,如添加多个查询条件、使用数据库预处理函数,以实现更多业务相关的功能。但是任何情况下超级用户 SQL 需要满足以下条件:
- 查询结果中必须包含 is_superuser 字段,is_superuser 应该显式的为 true
- 查询结果只能有一条,多条结果时只取第一条作为有效数据
如果不需要超级用户功能,注释并禁用该选项能有效提高效率
ACL SQL(acl_query)
进行 ACL 鉴权时,EMQ X 将使用当前客户端信息填充并执行用户配置的超级用户 SQL,如果没有启用超级用户 SQL 或客户端不是超级用户,则使用 ACL SQL 查询出该客户端在数据库中的 ACL 规则。
# etc/plugins/emqx_auth_pgsql.conf |
你可以在 ACL SQL 中使用以下占位符,执行时 EMQ X 将自动填充为客户端信息:
- %a:客户端地址
- %u:用户名
- %c:Client ID
你可以根据业务需要调整 ACL SQL,如添加多个查询条件、使用数据库预处理函数,以实现更多业务相关的功能。但是任何情况下 ACL SQL 需要满足以下条件:
- 查询结果中必须包含 allow、access、topic、clientid、username、ipaddr 字段,如果字段不想参与比对则使用
$all
字符串或者数据库NULL
值 - 查询结果可以有多条,多条结果时按照从上到下的顺序进行匹配
可以在 SQL 中调整查询条件、指定排序方式实现更高效率的查询。
Redis ACL
Redis ACL 使用外部 Redis 数据库存储 ACL 规则,可以存储大量数据、动态管理 ACL,方便与外部设备管理系统集成
插件:
emqx_auth_redis |
emqx_auth_redis 插件同时包含认证功能,可通过注释禁用。
Redis 连接信息
Redis 基础连接信息,需要保证集群内所有节点均能访问。
# etc/plugins/emqx_auth_redis.conf |
默认数据结构
Redis 认证插件默认配置下使用哈希表存储认证数据,使用 mqtt_user:
作为 Redis 键前缀,数据结构如下:
认证/超级用户
redis> hgetall mqtt_user:emqx |
默认配置下示例数据如下:
HMSET mqtt_user:emqx password public salt wivwiv |
ACL 规则数据
## 格式 |
Redis ACL 一条规则中定义了发布、订阅或发布/订阅的信息,在规则中的都是允许列表。
规则字段说明:
- ipaddr:设置 IP 地址
- username:连接客户端的用户名,此处的值如果设置为
$all
表示该规则适用于所有的用户 - clientid:连接客户端的 Client ID
- access:允许的操作:订阅(1),发布(2),订阅发布都可以(3)
- topic:控制的主题,可以使用通配符,并且可以在主题中加入占位符来匹配客户端信息,例如
t/%c
则在匹配时主题将会替换为当前客户端的 Client ID- %u:用户名
- %c:Client ID
默认配置下示例数据:
HSET mqtt_acl:emqx # 1 |
启用 Redis ACL 后并以用户名 emqx 成功连接后,客户端应当数据具有相应的主题权限。
超级用户查询命令(super cmd)
进行 ACL 鉴权时,EMQ X 将使用当前客户端信息填充并执行用户配置的超级用户查询命令,查询客户端是否为超级用户。客户端为超级用户时将跳过 ACL 查询命令。
# etc/plugins/emqx_auth_redis.conf |
你可以在命令中使用以下占位符,执行时 EMQ X 将自动填充为客户端信息:
- %u:用户名
- %c:Client ID
- %C:TLS 证书公用名(证书的域名或子域名),仅当 TLS 连接时有效
- %d:TLS 证书 subject,仅当 TLS 连接时有效
你可以根据业务需要调整超级用户查询命令,如添加多个查询条件、使用数据库预处理函数,以实现更多业务相关的功能。但是任何情况下超级用户查询命令需要满足以下条件:
- 查询结果中第一个数据必须为 is_superuser 数据
如果不需要超级用户功能,注释并禁用该选项能有效提高效率
ACL 查询命令(acl cmd)
进行 ACL 鉴权时,EMQ X 将使用当前客户端信息填充并执行用户配置的超级用户 SQL,如果没有启用超级用户 SQL 或客户端不是超级用户,则使用 ACL 查询命令查询出该客户端在数据库中的 ACL 规则。
# etc/plugins/emqx_auth_redis.conf |
你可以在 ACL 查询命令中使用以下占位符,执行时 EMQ X 将自动填充为客户端信息:
- %u:用户名
- %c:Client ID
你可以根据业务需要调整 ACL 查询命令,但是任何情况下 ACL 查询命令需要满足以下条件:
- 哈希中使用 topic 作为键,access 作为值
Redis ACL 规则需严格使用上述数据结构。
Redis ACL 中添加的所有规则都是 允许 规则,可以搭配 etc/emqx.conf
中 acl_nomatch = deny
使用。
MongoDB ACL
MongoDB ACL 使用外部 MongoDB 数据库存储 ACL 规则,可以存储大量数据、动态管理 ACL,方便与外部设备管理系统集成
插件:
emqx_auth_mongo |
emqx_auth_mongo 插件同时包含认证功能,可通过注释禁用。
MongoDB 连接信息
MongoDB 基础连接信息,需要保证集群内所有节点均能访问。
# etc/plugins/emqx_auth_mongo.conf |
默认数据结构
MongoDB 认证默认配置下需要确保数据库中有如下集合:
认证/超级集合
{ |
示例数据:
use mqtt |
ACL 规则集合
{ |
MongoDB ACL 一条规则中定义了发布、订阅和发布/订阅的信息,在规则中的都是允许列表。
规则字段说明:
- username:连接客户端的用户名
- clientid:连接客户端的 Client ID
- publish:允许发布的主题数值,支持通配符
- subscribe:允许订阅的主题数值,支持通配符
- pubsub:允许发布订阅的主题数值,支持通配符
主题可以使用通配符,并且可以在主题中加入占位符来匹配客户端信息,例如 t/%c
则在匹配时主题将会替换为当前客户端的 Client ID
- %u:用户名
- %c:Client ID
默认配置下示例数据:
use mqtt |
启用 MongoDB ACL 后并以用户名 emqx 成功连接后,客户端应当数据具有相应的主题权限。
超级用户查询(super_query)
进行 ACL 鉴权时,EMQ X 将使用当前客户端信息填充并执行用户配置的超级用户查询,查询客户端是否为超级用户。客户端为超级用户时将跳过 ACL 查询。
# etc/plugins/emqx_auth_mongo.conf |
同一个选择器的多个条件时实际查询中使用 MongoDB and
查询:
db.mqtt_user.find({ |
你可以在查询条件中使用以下占位符,执行时 EMQ X 将自动填充为客户端信息:
- %u:用户名
- %c:Client ID
你可以根据业务需要调整超级用户查询,如添加多个查询条件、使用数据库预处理函数,以实现更多业务相关的功能。但是任何情况下超级用户查询需要满足以下条件:
- 查询结果中必须包含 is_superuser 字段,is_superuser 应该显式的为 true
如果不需要超级用户功能,注释并禁用该选项能有效提高效率
ACL 查询(acl_query)
进行 ACL 鉴权时,EMQ X 将使用当前客户端信息填充并执行用户配置的超级用户查询,如果没有启用超级用户查询或客户端不是超级用户,则使用 ACL 查询 查询出该客户端在数据库中的 ACL 规则。
# etc/plugins/emqx_auth_mongo.conf |
同一个选择器的多个条件时实际查询中使用 MongoDB and
查询:
db.mqtt_acl.find({ |
多个选择器时实际查询中使用 MongoDB or
查询:
db.mqtt_acl.find({ |
你可以在 ACL 查询中使用以下占位符,执行时 EMQ X 将自动填充为客户端信息:
- %u:用户名
- %c:Client ID
MongoDB ACL 规则需严格使用上述数据结构。
MongoDB ACL 中添加的所有规则都是 允许 规则,可以搭配 etc/emqx.conf
中 acl_nomatch = deny
使用。
HTTP ACL
HTTP 认证使用外部自建 HTTP 应用认证授权数据源,根据 HTTP API 返回的数据判定授权结果,能够实现复杂的 ACL 校验逻辑。
插件:
emqx_auth_http |
emqx_auth_http 插件同时包含认证功能,可通过注释禁用。
要启用 HTTP ACL,需要在 etc/plugins/emqx_auth_http.conf
中配置以下内容:
ACL 授权原理
EMQ X 在设备发布、订阅事件中使用当前客户端相关信息作为参数,向用户自定义的认证服务发起请求权限,通过返回的 HTTP 响应状态码 (HTTP statusCode) 来处理 ACL 授权请求。
- 无权限:API 返回 4xx 状态码
- 授权成功:API 返回 200 状态码
- 忽略授权:API 返回 200 状态码且消息体 ignore
HTTP 请求信息
HTTP API 基础请求信息,配置证书、请求头与重试规则。
# etc/plugins/emqx_auth_http.conf |
进行发布、订阅认证时,EMQ X 将使用当前客户端信息填充并发起用户配置的 ACL 授权查询请求,查询出该客户端在 HTTP 服务器端的授权数据。
superuser 请求
首先查询客户端是否为超级用户,客户端为超级用户时将跳过 ACL 查询。
# etc/plugins/emqx_auth_http.conf |
ACL 授权查询请求
# etc/plugins/emqx_auth_http.conf |
请求说明
HTTP 请求方法为 GET 时,请求参数将以 URL 查询字符串的形式传递;POST、PUT 请求则将请求参数以普通表单形式提交(content-type 为 x-www-form-urlencoded)。
你可以在认证请求中使用以下占位符,请求时 EMQ X 将自动填充为客户端信息:
- %u:用户名
- %c:Client ID
- %a:客户端 IP 地址
- %r:客户端接入协议
- %P:明文密码
- %p:客户端端口
- %C:TLS 证书公用名(证书的域名或子域名),仅当 TLS 连接时有效
- %d:TLS 证书 subject,仅当 TLS 连接时有效
推荐使用 POST 与 PUT 方法,使用 GET 方法时明文密码可能会随 URL 被记录到传输过程中的服务器日志中。