EMQX开启MongoDB接入认证与订阅发布鉴权

背景

关于物联网平台设计一个最佳实践是:对接入平台的设备进行认证,并且对设备可以发布和订阅的主题进行权限控制
MQTT Broker 开启对接入设备的认证与订阅发布鉴权的意义在于增强系统的安全性。通过认证,可以确保只有经过授权的设备可以连接到Broker,从而防止未经授权的设备访问系统。而订阅发布鉴权则可以确保只有经过授权的设备可以发布和订阅特定的主题,从而控制数据的访问权限,保护敏感信息不被未授权的设备获取。这些安全措施有助于防止恶意攻击和数据泄露。

下面基于国产的 MQTT BrokerEMQX 以及它提供的 MongoDB 数据库认证与 ACL 插件: emqx_auth_mongo 实现对设备接入认证、订阅发布鉴权的功能。

启动EMQX,建立匿名客户端连接

[root@iot1 ~]# cd /usr/local/
[root@iot1 local]# cd emqx
[root@iot1 emqx]# ./bin/emqx_ctl status
Node 'emqx@127.0.0.1' not responding to pings.

# 以默认配置启动EMQX
[root@iot1 emqx]# ./bin/emqx start
There seem to be missing dynamic libs from the OS.
Using libs from /usr/local/emqx/dynlibs instead.
EMQ X Broker 4.4.2 is started successfully!

# 验证状态
[root@iot1 emqx]# ./bin/emqx_ctl status
Node 'emqx@127.0.0.1' 4.4.2 is started

# 查看防火墙状态
[root@iot1 emqx]# firewall-cmd --state
running

# 后面要通过远程客户端连接,这里直接关闭防火墙
[root@iot1 emqx]# systemctl stop firewalld.service
[root@iot1 emqx]# systemctl disable firewalld.service
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.

EMQX 默认配置下,与认证有关的插件都没有启动。

2023-12-24-1-DefaultConfig.jpg

以默认配置启动 EMQX 后,通过远程客户端工具进行匿名连接(即未输入用户名与密码),成功。

2023-12-24-2-AnonymousSuccess.jpg

修改MongoDB认证插件配置开启接入认证

[root@iot1 emqx]# vi ./etc/plugins/emqx_auth_mongo.conf
## MongoDB server list.
##
## Value: String
##
## Examples: 127.0.0.1:27017,127.0.0.2:27017...
auth.mongo.server = 127.0.0.1:27017

## MongoDB login user.
##
## Value: String
auth.mongo.username = you

## MongoDB password.
##
## Value: String
auth.mongo.password = guess

## MongoDB AuthSource
##
## Value: String
## Default: mqtt
auth.mongo.auth_source = device_access

## MongoDB database
##
## Value: String
auth.mongo.database = device_access

## -------------------------------------------------
## Auth Query
## -------------------------------------------------
## Password hash.
##
## Value: plain | md5 | sha | sha256 | bcrypt
auth.mongo.auth_query.password_hash = plain

## Authentication query.
auth.mongo.auth_query.collection = device

## Password mainly fields
##
## Value:  password | password,salt
auth.mongo.auth_query.password_field = secret

## Authentication Selector.
##
## Variables:
##  - %u: username
##  - %c: clientid
##  - %C: common name of client TLS cert
##  - %d: subject of client TLS cert
##
## auth.mongo.auth_query.selector = {Field}={Placeholder}
auth.mongo.auth_query.selector = access_name=%u

最后加载 ./bin/emqx_ctl plugins load emqx_auth_mongo ,如果是修改,则进行reload: ./bin/emqx_ctl plugins reload emqx_auth_mongo ;此时,通过 EMQX 自带的 Web 控制台 Dashboard ,可以看到 MongoDB 认证插件已启用。
需要注意的是,确保配置的 MongoDB 可以连接成功,否则 emqx_auth_mongo 插件无法加载。

通过 MQTT 客户端进行无密码接入,发现依然可以连接成功!这是因为我们虽然开启了 MongoDB 数据库的认证,但是 EMQX 默认还开启了匿名接入,我们需要到 EMQX 的全局配置文件中关闭匿名配置。

[root@iot1 emqx]# vi ./etc/emqx.conf
##--------------------------------------------------------------------
## Authentication/Access Control
##--------------------------------------------------------------------
## Allow anonymous authentication by default if no auth plugins loaded.
## Notice: Disable the option in production deployment!
##
## Value: true | false
allow_anonymous = false

## Allow or deny if no ACL rules matched.
##
## Value: allow | deny
acl_nomatch = deny

# 这个需要重启EMQX服务
[root@iot1 emqx]# ./bin/emqx restart

再次尝试通过远程客户端工具进行匿名连接,失败~

2023-12-24-3-AnonymousFail.jpg

生成设备接入秘钥信息

基于 Express 框架创建 Node.js 后端项目,实现一个新增接口,返回设备信息三元组:产品名称,设备名称,设备秘钥。

数据模型

  • device.model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// mongoose表名会自动增加s,通过指定collection名称进行覆盖
const deviceSchema = new Schema({
    //ProductName
    product_name: {
        type: String,
        required: true
    },
    //DeviceName
    device_name: {
        type: String,
        required: true,
    },
    //接入EMQX时使用的username
    access_name: {
        type: String,
        required: true
    },
    //secret
    secret: {
        type: String,
        required: true,
    },
    // 可接入状态
    status: String,
    // 上次状态更新时间
    last_status_update: Number,
}, {
    collection: "device"
});

//定义 device.toJSONObject
deviceSchema.methods.toJSONObject = function() {
    return {
        product_name: this.product_name,
        device_name: this.device_name,
        secret: this.secret
    }
}

deviceSchema.methods.getACLRule = function() {
    const publish = [
        `report_data/${this.product_name}/${this.device_name}/+/+`,
        `update_status/${this.product_name}/${this.device_name}/+`,
    ];
    const subscribe = [];
    const pubsub = [];
    return {
        publish: publish,
        subscribe: subscribe,
        pubsub: pubsub
    }
}

const Device = mongoose.model("Device", deviceSchema);
module.exports = Device;
  • device_acl.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const deviceACLSchema = new Schema({
    //接入EMQX时使用的username
    access_name: {
        type: String,
        required: true
    },
    publish: Array,
    subscribe: Array,
    pubsub: Array
}, {
    collection: "device_acl"
});

const DeviceACL = mongoose.model("DeviceACL", deviceACLSchema);
module.exports = DeviceACL;

路由接口

  • devices.js
const express = require('express');
const Device = require("../models/device");
const shortid = require("shortid");
const router = express.Router();
let DeviceACL = require('../models/device_acl');

router.post("/", function(req, res) {
    console.log(`body: ${req.body.product_name}`);
    let productName = req.body.product_name;
    let deviceName = shortid.generate();
    let secret = shortid.generate();
    let accessName = `${productName}/${deviceName}`;

    let device = new Device({
        product_name: productName,
        device_name: deviceName,
        secret: secret,
        access_name: accessName,
        status: "active"
    });

    device.save(function(err) {
        if (err) {
            res.status(500).send(err);
        } else {
            let aclRule = device.getACLRule();
            let deviceACL = new DeviceACL({
                access_name: device.access_name,
                publish: aclRule.publish,
                subscribe: aclRule.subscribe,
                pubsub: aclRule.pubsub
            });
            deviceACL.save(function() {
                res.json({
                    product_name: productName,
                    device_name: deviceName,
                    secret: secret
                })
            });
        }
    })
});

2023-12-24-4-GenerateAuth.jpg

执行生成设备三元组信息后,数据成功写入 MongoDB ,当然,这里包括设备的认证信息,以及发布订阅权限信息。

2023-12-24-5-Device.jpg

2023-12-24-6-DeviceACL.jpg

使用生成的设备接入信息,作为用户名与密码,连接 MQTT Broker ,成功。

2023-12-24-7-AuhSuccess.jpg

修改MongoDB认证插件配置开启发布订阅鉴权

## ACL Selector.
##
## Multiple selectors could be combined with '$or'
##   when query acl from mongo.
##
## e.g.
##
## With following 2 selectors configured:
##
## auth.mongo.acl_query.selector.1 = username=%u
## auth.mongo.acl_query.selector.2 = username=$all
##
## And if a client connected using username 'ilyas',
##   then the following mongo command will be used to
##   retrieve acl entries:
##
## db.mqtt_acl.find({$or: [{username: "ilyas"},  {username: "$all"}]});
##
## Variables:
##  - %u: username
##  - %c: clientid
##
## Examples:
##
## auth.mongo.acl_query.selector.1 = username=%u,clientid=%c
## auth.mongo.acl_query.selector.2 = username=$all
## auth.mongo.acl_query.selector.3 = clientid=$all
auth.mongo.acl_query.collection = device_acl
auth.mongo.acl_query.selector = access_name=%u

设备的 ACL 存储到了 MongoDBdevice_acl 表中,进行匹配时查询 access_name 与客户端发来的 username 进行匹配。

发布数据到任意一个主题,失败,没有权限。

2023-12-24-8-PubFail.jpg

根据 ACL 表里写入的主题信息进行发布,成功。

2023-12-24-9-PubSuccess.jpg

其他API

除了生成设备接入信息三元组的接口外,还实现了获取设备三元组信息,以及设备的启用、禁用、删除接口,方便物联网平台对设备进行管理。

2023-12-24-10-API.jpg

小总结

以上记录了基于 EMQX 与它提供的 MongoDB 数据库认证与 ACL 插件: emqx_auth_mongo 实现对设备接入认证、订阅发布鉴权的功能, MQTT Broker 开启对接入设备的认证、订阅发布鉴权:

  1. 安全性:认证可以确保只有经过授权的设备可以连接到Broker,防止未经授权的设备访问和篡改数据。
  2. 控制权限:通过认证可以对不同的设备设置不同的权限,例如读取、发布或订阅特定主题的权限,从而实现更精细的访问控制。
  3. 跟踪和监控:认证可以帮助跟踪和监控连接到Broker的设备,记录设备的活动和行为,有助于排查问题和进行安全审计。

因此,开启对接入设备的认证可以提高系统的安全性和可控性。


If you have any questions or any bugs are found, please feel free to contact me.

Your comments and suggestions are welcome!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/279274.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【IEEE解刊】IF4.4实力强劲,国人占比第一,好投吗?(附中科院高分区快刊)

计算机类 • 好刊解读 今天小编带来IEEE旗下计算机领域高分好刊,如您有投稿需求,可作为重点关注!后文有相关领域真实发表案例,供您投稿参考~ 01 期刊简介 IEEE Systems Journal ✅出版社:IEEE ✅ISSN:1…

【Bootstrap学习 day4】

Bootstrap5 列表组 使用Bootstrap创建列表 可以创建三种不类型的HTML列表: 无序列表—顺序无关紧要的项目列表。无序列表中的列表标有项目符号,例如。、等ul>li有序列表—顺序确实很重要的项目列表。有序列表中的列表项用数字标记,例如1、…

docker重量级容器预警监控系统CIG

文章目录 一、介绍CIG二、CIG,compose部署2.1 docker-compose运行CIG2.2 grafana配置1.配置数据源2.选择influxdb数据源3.配置数据库的连接信息4.create dashboard5.配置数据源6.大功告成 一、介绍CIG C:CAdvisor,监控收集,默认存储最近2分钟…

MYSQL的UPDATE时锁表机制

(笔记,只为获取流量券) MySQL中,UPDATE 操作涉及到行级锁和表级锁的概念,具体取决于事务隔离级别和被更新的条件, 无索引的情况下: 当表没有索引的情况下,UPDATE 操作通常会涉及到表级锁。这是…

机器学习的一般步骤

机器学习专注于让机器从大量的数据中模拟人类思考和归纳总结的过程,获得计算模型并自动判断和推测相应的输出结果。机器学习的一般步骤可以概括为以下几个阶段: 数据收集和准备: 收集与问题相关的数据,并确保数据的质量和完整性。…

详解—数据结构—<常用排序>基本实现和代码分析

目录 一.排序的概念及其运用 1.1排序的概念 1.2排序运用​编辑 1.3 常见的排序算法​编辑 二.常见排序算法的实现 2.1 插入排序 2.1.1基本思想: 2.1.2直接插入排序: 2.1.3 希尔排序( 缩小增量排序 ) 2.2 选择排序 2.2.1基本思想: …

unity 保存和加载窗口布局

这么简单的事网上一堆废话文章 右上角,Layout点开后有保存和删除 要切换布局点红框里的已经保存的布局

Go语言学习第二天

Go语言数组详解 var 数组变量名 [元素数量]Type 数组变量名:数组声明及使用时的变量名。 元素数量:数组的元素数量,可以是一个表达式,但最终通过编译期计算的结果必须是整型数值,元素数量不能含有到运行时才能确认大小…

2020年认证杯SPSSPRO杯数学建模B题(第一阶段)分布式无线广播全过程文档及程序

2020年认证杯SPSSPRO杯数学建模 B题 分布式无线广播 原题再现: 以广播的方式来进行无线网通信,必须解决发送互相冲突的问题。无线网的许多基础通信协议都使用了令牌的方法来解决这个问题,在同一个时间段内,只有唯一一个拿到令牌…

是时候将javax替换为Jakarta了

开始 相信很多朋友在使用新版本的Spring的时候,发现了一些叫jakarta的包,看起来有点陌生。 很多时候,比较纠结不知道该导入哪一个包。 jakarta其实就是之前的javax。 主要JavaEE相关的,从之前javax名字也可以看出来&#xff0…

LeetCode刷题--- 单词搜索

个人主页:元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​​http://t.csdnimg.cn/hKh2l 前言:这个专栏主要讲述…

启封涂料行业ERP需求分析和方案分享

涂料制造业是一个庞大而繁荣的行业 它广泛用于建筑、汽车、电子、基础设施和消费品。涂料行业生产不同的涂料,如装饰涂料、工业涂料、汽车涂料和防护涂料。除此之外,对涂料出口的需求不断增长,这增加了增长和扩张的机会。近年来,…

Livox-Mid-360 固态激光雷达ROS格式数据分析

前言: Livox-Mid-360 官方采用livox_ros_driver2ROS功能包发布ROS格式的数据,livox_ros_driver2可以把Livox原始雷达数据转化成ROS格式并以话题的形式发布出去。 下面列举一些雷达的基本概念: 点云帧:雷达驱动每次向外发送的一…

基于MATLAB的卡方分布,瑞利分布,T与F分布(附完整代码与例题)

一. 卡方分布 1.1 数学理论 首先我们来看下伽玛分布的概率密度函数: 其中: 令,就可以得到一个新的分布,这个分布在概率论上被叫做卡方分布。卡方分布也可以写做分布。其概率密度函数则为: 卡方分布要求参数k为正整数…

利用 PEB_LDR_DATA 结构枚举进程模块信息

1. 引言 我们常常通过很多方法来获取进程的模块信息,例如 EnumProcessModules 函数、CreateToolhelp32Snapshot 函数、WTSEnumerateProcesses 函数、ZwQuerySystemInformation 函数等。但是调用这些接口进行模块枚举的原理是什么我们并不知道。通过学习 PEB 中 PEB…

polar CTF上传

1、题目 2、经过测试.htaccess绕过 三行代码解析: 将上传的.jpg文件解析成php文件 auto_append_file包含上传的文件 将上传的文件进行解码 AddType application/x-httpd-php .jpg php_value auto_append_fi\ le "php://filter/convert.base64-decode/resourc…

数据结构与算法-排序

🌞入冬 时寒 添衣 勿病 要开心 排序 🎈1.排序的基本概念🎈2.排序的分类🔭2.1插入排序🔎2.1.1直接插入排序🔎2.1.2折半插入排序🔎2.1.3希尔排序 🔭2.2交换排序🔎2.2.1冒泡…

Python中的并发编程(7)异步编程

异步编程 Python3.4后新增了asyncio模块,支持异步编程。 异步是在一个线程中通过任务切换的方式让多个任务”同时“进展。asyncio不涉及线程/进程切换,减少了线程/进程创建、上下文切换的开销,更轻量级。 asyncio的核心是事件循环&#xff0…

【设计模式】外观模式

文章目录 前言一、外观模式1.案例2.优缺点3.使用场景4.源码解析 总结 前言 【设计模式】外观模式 一、外观模式 有些人可能炒过股票,但其实大部分人都不太懂,这种没有足够了解证券知识的情况下做股票是很容易亏钱的,刚开始炒股肯定都会想&am…

c语言:把二维数组降至一维|练习题

一、题目 把二维数组降为一围数组 如图&#xff1a; 二、代码截图【带注释】 三、源代码【带注释】 #include <stdio.h> int main() { int arr2[3][3];//设置二维数组 int arr1[10];//设置一维数组 int z0;//一维数组自增量 printf("输入一个二维数…