You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EMQX 5.8.0如何动态添加ACL规则限制客户端主题访问?

问题分析与解决方案

你的操作错误点

  • 核心逻辑误解:你混淆了「EMQX ACL规则管理API」和「HTTP ACL回调」的作用。HTTP ACL回调是EMQX在做权限检查时,把请求发给你的Flask服务,由你的服务直接返回允许/拒绝即可,完全不需要调用EMQX的API去创建ACL规则。当前脚本试图给每个请求新增一条规则,不仅逻辑错误,还会导致EMQX内的ACL规则无限膨胀。
  • API地址与端口错误:EMQX 5.x的ACL规则管理API是/api/v5/authorization/rules(而非acl/rules),但你根本不需要用这个API实现动态ACL。另外你的Flask服务监听8080端口,和EMQX默认的API端口冲突,导致两个服务无法同时运行。
  • 主题匹配逻辑漏洞:直接用topic.startswith(client_id)会导致误判,比如clientId为device1时,主题device12/abc会被错误允许,应该加上分隔符/来精确匹配前缀。

更简便的实现方式:使用EMQX内置文件ACL(无需额外服务,支持热加载)

EMQX 5.x支持文件ACL热加载,修改配置后无需重启服务,执行命令即可生效。

  1. 编辑etc/acl.conf,添加以下规则:
# 允许客户端发布/订阅以自身clientId开头的主题(%c代表当前客户端的clientId,用userName则换成%u)
allow {
    client_id = "%c"
    action = "publish"
    topic = "%c/#"
}
allow {
    client_id = "%c"
    action = "subscribe"
    topic = "%c/#"
}

# 禁止所有客户端订阅my_device/#
deny {
    action = "subscribe"
    topic = "my_device/#"
}

# 默认拒绝所有未匹配的请求
deny all
  1. 执行热加载命令,规则立即生效:
emqx ctl acl reload

若需HTTP ACL回调(复杂逻辑场景):修正后的实现

如果必须用外部服务处理权限逻辑,按以下步骤修正:

  1. 修改EMQX配置,启用HTTP ACL回调:
    编辑etc/emqx.conf,添加配置:
authorization {
    sources = [
        {
            type = http
            url = "http://你的Flask服务IP:8081/acl"  # 改用8081端口避免冲突
            method = post
            body = "json"
            headers = {
                "Content-Type" = "application/json"
            }
            timeout = 5s
        }
    ]
}

修改后重启一次EMQX即可,后续修改Flask脚本无需重启EMQX。

  1. 修正Flask脚本(直接判断权限返回结果):
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/acl', methods=['POST'])
def acl_check():
    data = request.json
    client_id = data.get('clientid')
    topic = data.get('topic')
    action = data.get('action')

    # 禁止订阅my_device/#
    if action == 'subscribe' and topic == 'my_device/#':
        return jsonify({"result": "deny"}), 200

    # 精确匹配主题前缀(带/避免误判)
    if topic.startswith(f"{client_id}/"):
        return jsonify({"result": "allow"}), 200
    else:
        return jsonify({"result": "deny"}), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8081)

内容的提问来源于stack exchange,提问作者Indian Gooner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 01:15:54