MQTT broker搭建并用SSL加密
系统为centos,基于emqx搭建broker,流程参考官方。
安装好后,用ssl加密。
进入/etc/emqx/certs,可以看到

分别为
- cacert.pem CA 文件
- cert.pem 服务端证书
- key.pem 服务端key
- client-cert.pem 客户端证书
- client-key.pem 客户端key
编辑emqx配置:vim /etc/emqx/emqx.conf,添加ssl配置:
listeners.ssl.default {# 端口bind = "0.0.0.0:8883"ssl_options {cacertfile = "/etc/emqx/certs/cacert.pem" #CA文件certfile = "/etc/emqx/certs/cert.pem" #服务端证书keyfile = "/etc/emqx/certs/key.pem" #服务端keyverify = verify_peer # 双向认证fail_if_no_peer_cert = true}
}
再在客户端(如MQTTX)配置连接信息:
Springboot订阅MQTTS
添加依赖
<!--mqtt--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-integration</artifactId></dependency><dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-stream</artifactId></dependency><dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-mqtt</artifactId></dependency><!--ssl--><dependency><groupId>org.bouncycastle</groupId><artifactId>bcpkix-jdk15on</artifactId><version>1.64</version></dependency>
配置
spring:mqtt:provider:#MQTTS服务地址,端口号默认8883,如果有多个,用逗号隔开url: ssl://192.168.1.xx:8883#用户名username: xx#密码password: xxxx#客户端id(不能重复)client:id: provider-id#MQTT默认的消息推送主题,实际可在调用接口是指定default:topic: topicconsumer:url: ssl://192.168.1.xx:8883#用户名username: xx#密码password: xxxx#客户端id(不能重复)client:id: consumer-id#MQTT默认的消息推送主题,实际可在调用接口时指定default:topic: topic
Mqtt配置
@Configuration
public class MqttConsumerConfig {@Value("${spring.mqtt.consumer.username}")private String username;@Value("${spring.mqtt.consumer.password}")private String password;@Value("${spring.mqtt.consumer.url}")private String hostUrl;@Value("${spring.mqtt.consumer.client.id}")private String clientId;@Value("${spring.mqtt.consumer.default.topic}")private String defaultTopic;// 把证书文件放在在resource的ssl_certs目录下String caFilePath = "/ssl_certs/cacert.pem";String clientCrtFilePath = "/ssl_certs/client-cert.pem";String clientKeyFilePath = "/ssl_certs/client-key.pem";/*** 客户端对象*/private MqttClient client;/*** 在bean初始化后连接到服务器*/@PostConstructpublic void init() {connect();}/*** 客户端连接服务端*/@SneakyThrowspublic void connect() {
// try {//创建MQTT客户端对象client = new MqttClient(hostUrl, clientId, new MemoryPersistence());//连接设置MqttConnectOptions options = new MqttConnectOptions();SSLSocketFactory socketFactory = getSocketFactory(caFilePath,clientCrtFilePath, clientKeyFilePath, "");options.setSocketFactory(socketFactory);/*允许所有host连接*/options.setSSLHostnameVerifier((s, sslSession) -> true);/*不配置可能出现报错java.security.cert.CertificateException: No subject alternative names present*/options.setHttpsHostnameVerificationEnabled(false);//是否清空session,设置为false表示服务器会保留客户端的连接记录,客户端重连之后能获取到服务器在客户端断开连接期间推送的消息//设置为true表示每次连接到服务端都是以新的身份options.setCleanSession(true);//设置连接用户名options.setUserName(username);//设置连接密码options.setPassword(password.toCharArray());//设置超时时间,单位为秒options.setConnectionTimeout(100);//设置心跳时间 单位为秒,表示服务器每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线options.setKeepAliveInterval(20);//设置遗嘱消息的话题,若客户端和服务器之间的连接意外断开,服务器将发布客户端的遗嘱信息options.setWill("willTopic", (clientId + "与服务器断开连接").getBytes(), 0, false);options.setAutomaticReconnect(true);//设置回调client.setCallback(new MqttCallbackImpl());client.connect(options);System.out.println(" 客户端连接成功 ");//订阅主题//消息等级,和主题数组一一对应,服务端将按照指定等级给订阅了主题的客户端推送消息int[] qos = {1, 1};//主题String[] topics = {"topicX#", "topicY#"};//订阅主题
// client.subscribe("topicX",1);client.subscribe(topics);
// } catch (Exception e) {
// e.printStackTrace();
// }}/*** 断开连接*/public void disConnect() {try {client.disconnect();} catch (MqttException e) {e.printStackTrace();}}/*** 订阅主题*/public void subscribe(String topic, int qos) {try {client.subscribe(topic, qos);} catch (MqttException e) {e.printStackTrace();}}private static SSLSocketFactory getSocketFactory(final String caCrtFile,final String crtFile, final String keyFile, final String password)throws Exception {ClassPathResource caCrtFileRes = new ClassPathResource(caCrtFile);ClassPathResource crtFileRes = new ClassPathResource(crtFile);ClassPathResource keyFileRes = new ClassPathResource(keyFile);// add BouncyCastle providerSecurity.addProvider(new BouncyCastleProvider());// load CA certificateX509Certificate caCert = null;BufferedInputStream bis = new BufferedInputStream(caCrtFileRes.getStream());CertificateFactory cf = CertificateFactory.getInstance("X.509");while (bis.available() > 0) {caCert = (X509Certificate) cf.generateCertificate(bis);// System.out.println(caCert.toString());}// load client certificatebis = new BufferedInputStream(crtFileRes.getStream());X509Certificate cert = null;while (bis.available() > 0) {cert = (X509Certificate) cf.generateCertificate(bis);// System.out.println(caCert.toString());}// load client private keyPEMParser pemParser = new PEMParser(new InputStreamReader(keyFileRes.getStream()));Object object = pemParser.readObject();PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");KeyPair key;if (object instanceof PEMEncryptedKeyPair) {System.out.println("Encrypted key - we will use provided password");key = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));} else {System.out.println("Unencrypted key - no password needed");key = converter.getKeyPair((PEMKeyPair) object);}pemParser.close();// CA certificate is used to authenticate serverKeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());caKs.load(null, null);caKs.setCertificateEntry("ca-certificate", caCert);TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");tmf.init(caKs);// client key and certificates are sent to server so it can authenticate// usKeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());ks.load(null, null);ks.setCertificateEntry("certificate", cert);ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(),new java.security.cert.Certificate[]{cert});KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());kmf.init(ks, password.toCharArray());// finally, create SSL socket factorySSLContext context = SSLContext.getInstance("TLSv1.2");context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);return context.getSocketFactory();}}
@Slf4j
@Component
public class MqttCallbackImpl implements MqttCallback {@Overridepublic void connectionLost(Throwable throwable) {log.info("[MQTT] 连接断开");}@Overridepublic void messageArrived(String topic, MqttMessage message) throws Exception {String msg = new String(message.getPayload());log.info(String.format("接收消息主题 : %s", topic));log.info(String.format("接收消息Qos : %d", message.getQos()));log.info(String.format("接收消息内容 : %s", msg));log.info(String.format("接收消息retained : %b", message.isRetained()));}@Overridepublic void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {log.info("发送消息成功");}
}相关文章:
MQTT broker搭建并用SSL加密
系统为centos,基于emqx搭建broker,流程参考官方。 安装好后,用ssl加密。 进入/etc/emqx/certs,可以看到 分别为 cacert.pem CA 文件cert.pem 服务端证书key.pem 服务端keyclient-cert.pem 客户端证书client-key.pem 客户端key 编辑emqx配…...
深度剖析AI情感陪伴类产品及典型应用 Character.ai
前段时间AI圈内C.AI的受够风波可谓是让大家都丈二摸不着头脑,连C.AI这种行业top应用都要找谋生方法了!投资人摸不着头脑,用户们更摸不着头脑。在这之前断断续续玩了一下这款产品,这次也是乘着这个风波,除了了解一下为什…...
[数据集][目标检测]街头摊贩识别检测数据集VOC+YOLO格式758张1类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):758 标注数量(xml文件个数):758 标注数量(txt文件个数):758 标注类别…...
面试准备-3
BIO/NIO/AIO区别的区别? 同步阻塞IO : 用户进程发起一个IO操作以后,必须等待IO操作的真正完成后,才能继续运行。 同步非阻塞IO: 客户端与服务器通过Channel连接,采用多路复用器轮询注册的Channel。提高吞吐量和可靠性。用户进程发…...
Unity教程(十五)敌人战斗状态的实现
Unity开发2D类银河恶魔城游戏学习笔记 Unity教程(零)Unity和VS的使用相关内容 Unity教程(一)开始学习状态机 Unity教程(二)角色移动的实现 Unity教程(三)角色跳跃的实现 Unity教程&…...
利用深度学习实现验证码识别-3-ResNet18
在当今数字化时代,验证码作为一种重要的安全验证手段,广泛应用于各种网络场景。然而,传统的验证码识别方法往往效率低下,准确率不高。今天,我们将介绍一种基于 ResNet18 的验证码识别方法,它能够高效、准确…...
UDP通信实现
目录 前言 一、基础知识 1、跨主机传输 1、字节序 2、主机字节序和网络字节序 3、IP转换 2、套接字 3、什么是UDP通信 二、如何实现UDP通信 1、socket():创建套接字 2、bind():绑定套接字 3、sendto():发送指定套接字文件数据 4、recvfrom():接收指定地址信息的数据 三…...
windows下使用vscode编写运行以及调试C/C++
vscode支持类似于vs的断点调试c/c,也可以直接编译&运行c/c 先是编译运行 c/c的方法 微软官方起初设定的科学做法(这也是现在的科学做法)是通过在vscode集成控制台写命令行的方式来实现编译运行程序的,但也可以通过code runner插件…...
python容器4--集合
(1) 什么是集合 集合:Python中使用关键字set表示 集合中存储多个、没有顺序的、不能重复的、可以是不同类型的多个数据! (2) 集合的声明 python中通过set()或者花括号声明空集合、非空集合 # 声明空集…...
MySQL record 01 part
更改密码: alter user rootlocalhost identified with mysql_native_password by ‘123456’; 注意: 在命令行方式下,每条MySQL的命令都是以分号结尾的,如果不加分号,MySQL会继续等待用户输入命令,直到MyS…...
2024年高教社杯全国大学生数学建模竞赛A题思路(2024数学建模国赛A题思路)
A题 “板凳龙” 闹元宵 “板凳龙”,又称“盘龙”,是浙闽地区的传统地方民俗文化活动。人们将少则几十条,多则上百条的板凳首尾相连,形成蜿蜒曲折的板凳龙。盘龙时,龙头在前领头,龙身和龙尾相随盘旋,整体呈圆盘状。一般来说,在舞龙队能够自如地盘入和盘出的前提下,盘龙…...
Go语言基础语法 20240904更新
代码开源地址 https://github.com/zhangdapeng520/zdpgo_basic 快速入门 示例代码: package mainimport "fmt"func main() {fmt.Println("Hello World") }第一行代码 package 用来声明包名。main包时整个程序的入口包,在一个Go语…...
软件测试 | 性能测试
性能测试的概念 为了 发现系统性能问题 或 获取系统性能相关指标 而进行的测试。 常见性能测试指标 并发数 即并发用户数。 从业务层面看,并发用户数指的是 实际使用系统的用户总数。从后端服务器层面看,指的是 web服务器在一段时间内处理浏览器请求而建…...
Arduino IDE
Arduino IDE(集成开发环境)的安装过程是一个相对直观且易于操作的流程,主要步骤包括下载、安装和配置。以下将详细阐述Arduino IDE的安装过程,同时提供一些背景信息和注意事项,确保安装过程顺利进行。 一、Arduino ID…...
统计学习方法与实战——统计学习方法之感知机
感知机 感知机三要素分析模型策略损失函数选择 算法原始形式对偶形式 相关问题 例子iris数据集分类实战数据集查看 显示结果sklearn 实战感知机 习题解答习题2.1解题步骤反证法 习题2.2习题2.3凸壳线性可分线性可分证明凸壳不相交证明充分性:凸壳不相交\Rightarrow⇒…...
语言学习有捷径?没错!这4个方法让你轻松搞定英语翻译
现在全世界都在用英语,这门语言真的超级重要。不管你是学习、上班还是出去玩,会点英语翻译肯定能帮上大忙。但是,对很多人来说,翻译英语还是挺难的。别急,今天我就来给你介绍几个超好用的英语翻译工具,让你…...
聊一聊大型网站稳定性建设思路
目录 架构阶段的稳定性建设项目 编码阶段的稳定性建设 测试阶段的稳定性建设 发布阶段的稳定性建设 运行阶段的稳定性建设项目 故障发生时的稳定性建设 网站稳定性的建设是一项综合的系统工程,就像人的健康一样,如果平时不注意健康饮食、不注意锻炼…...
Nginx常用配置
Windows版本Nginx开机自启动 可直接下载已经配置好的文件,点击即可下载:Windows版本Nginx1.26.0 下载WinSW v2.12.0 首先从https://github.com/winsw/winsw/releases下载WinSW v2.12.0 下载Nginx 下载地址https://nginx.org/en/download.html 修…...
前端开发中遇到的小问题以及解决方案记录2
1、H5中适配屏幕的工具-postcss-px-to-viewport postcss-px-to-viewport。因为设计稿一般给的都是375px宽度的,所以假如一个字体是16px,那么在开发中不能直接写死为16px,因为各个厂商的手机屏幕大小是不同的,所以要根据屏幕大小去…...
Qt-常用控件(3)-输入类
1. QLineEdit QLineEdit 用来表示单行输入框.可以输入一段文本,但是不能换行 核心属性 属性说明text输入框中的文本inputMask输入内容格式约束maxLength最大长度frame是否添加边框echoMode显示方式. QLineEdit::Normal :这是默认值,文本框会显示输入的文本。QLineE…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
