emqx是一种基于mqtt协议实现的消息框架,目前很多地方已经开始使用。简单的emqx安装配置,其实就可以作为一个broker来使用,客户端只需要通过ip、端口、用户名、密码、clientid就可以连接了,至于发送消息,直接在发送的时候指定topic即可。

简单的emqx安装配置,使用的协议是:mqtt:tcp,使用的url是tcp://ip:1883。这种方式,其实可以很容易被模拟(理论上的可能),所以有了mqtts:tls协议,一般使用ssl协议来实现。这也是本文所要阐述的问题。

我在配置ssl证书的时候,服务启动没问题,最后客户端连接,死活连接失败。最后看了官方的文档,按照那个文档很容易就配置成功,并且客户端连接也成功了。

其实我大概知道我配置失败的原因,可能是因为证书中的一个跟主机ip相关的设置问题,但是这个问题我按照一些博客的提示做了修改,但是后来还是没有成功,很郁闷,最后按照官方配置,很快设置好了。思路基本一模一样,而且配置证书的步骤也都类似,先生成私钥,然后生成证书请求,最后根据根证书生成服务端证书和客户端证书。

emqx的下载安装这里不做过多的说明,在官网直接下载,解压然后运行bin/emqx start就可以了。

emqx安装目录下有一个etc/certs目录,它自带了一些根证书、服务端证书、客户端证书,但是为了保险起见,最好自己根据自己的主机地址生成。

下面基本是按照emqx官方的一篇博客来配置的,就是主机地址做了修改。

以下的证书配置,是自签名证书,不是花钱购买的那种服务器证书。

1、生成根证书私钥

openssl genrsa -out ca.key 2048

2、生成根证书

openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.pem

这一步会有交互提示,需要输入省份、城市、公司、组织、姓名、右键,随便填写就可以,这里的信息不会影响根证书使用。

3、生成服务端证书私钥

openssl genrsa -out emqx.key 2048

4、生成服务端证书请求

按照官方博客的意思,这里需要手动创建一个openssl.cnf的文件,其实主要就是设置IP地址

[req]
default_bits  = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
countryName = CN
stateOrProvinceName = Hubei
localityName = Wuhan
organizationName = EMQX
commonName = CA
[req_ext]
subjectAltName = @alt_names
[v3_req]
subjectAltName = @alt_names
[alt_names]
IP.1 = 192.168.226.100
DNS.1 = 192.168.226.100

如果你的服务器是虚拟机,只需要修改IP.1的值即可。

执行如下命令生成服务端证书请求:

openssl req -new -key ./emqx.key -config openssl.cnf -out emqx.csr

私钥的生成,就使用了openssl.cnf配置文件 ,所以我之前的配置失败,应该是这里的IP设置问题。但是我确实根据某些博客的提示,设置subj "/CN=192.168.226.100",但是不生效。

5、生成服务端证书

openssl x509 -req -in ./emqx.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out emqx.pem -days 3650 -sha256 -extensions v3_req -extfile openssl.cnf

6、生成客户端证书私钥

openssl genrsa -out client.key 2048

7、生成客户端证书请求

openssl req -new -key client.key -out client.csr -subj "/C=CN/ST=Zhejiang/L=Hangzhou/O=EMQX/CN=client"

8、生成客户端证书

openssl x509 -req -days 3650 -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client.pem

一顿操作之后certs目录下生成的文件:

以上,只是生成了相关证书,在emqx的配置文件etc/emqx.conf中还需要做相关设置:

listener.ssl.external.keyfile = etc/certs/emqx.key
listener.ssl.external.certfile = etc/certs/emqx.pem
listener.ssl.external.cacertfile = etc/certs/ca.pem
listener.ssl.external.verify = verify_peer
listener.ssl.external.fail_if_no_peer_cert = true

这几个主要的配置在原来的emqx.conf中都有,只需要打开或者修改配置值即可,主要是证书的名字。

重启emqx服务,验证。bin/emqx restart

这里使用mqttbox来验证,其实mqtt.x也是可以的,客户端需要的文件:ca.pem,client.pem,client.key

普通的mqtt/tcp协议连接配置:

mqtts/tls协议连接配置:

配置需要注意的地方在上图中已经标识出来了,协议类型:mqtts/tls ,证书类型:自签名证书,ca文件:ca.pem,客户端证书:client.pem,客户端私钥:client.key。

配置完成,保存,可以看到连接状态变为绿色,如果是红色,那么就需要检查证书是否配置正确,包括生成和在emqx.conf配置文件中的设置。

发送消息测试:

下面通过java代码来验证,这里使用springboot+spring-integration-mqtt来实现。

maven工程的pom.xml

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-integration</artifactId></dependency><dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-mqtt</artifactId></dependency><dependency><groupId>org.eclipse.paho</groupId><artifactId>org.eclipse.paho.client.mqttv3</artifactId><version>1.2.5</version></dependency><dependency><groupId>org.bouncycastle</groupId><artifactId>bcpkix-jdk15on</artifactId><version>1.47</version></dependency>

application-dev.yml

mqtt:serverURIs: ssl://192.168.226.100:8883username: adminpassword: publicclient:id: ${random.value}topic: test

MqttConfig.java

package com.huali.mec.receiver.config;
import java.util.Objects;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;import com.huali.mec.receiver.util.SslUtil;
@IntegrationComponentScan
@Configuration
public class MqttConfig {public static final Logger log  = LoggerFactory.getLogger(MqttConfig.class);public static final String OUTPUT_CHANNEL = "mqttOutputChannel";public static final String INPUT_CHANNEL = "mqttInputChannel";@Value("${mqtt.username}")private String username ;@Value("${mqtt.password}")private String password ;@Value("${mqtt.serverURIs}")private String serverURIs ;@Value("${mqtt.client.id}")private String clientId;@Value("${mqtt.topic}")private String defaultTopic ;@Beanpublic MqttPahoClientFactory clientFactory() {final MqttConnectOptions options = new MqttConnectOptions();options.setServerURIs(new String[] {serverURIs});options.setUserName(username);options.setPassword(password.toCharArray());options.setKeepAliveInterval(10);options.setAutomaticReconnect(true);try {options.setSocketFactory(SslUtil.getSocketFactory("src/main/resources/ssl/ca.pem", "src/main/resources/ssl/client.pem", "src/main/resources/ssl/client.key", password));} catch (Exception e) {e.printStackTrace();}final DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();factory.setConnectionOptions(options);return factory;}@Bean(value = OUTPUT_CHANNEL)public MessageChannel mqttOutChannel() {return new DirectChannel();}@Bean@ServiceActivator(inputChannel = OUTPUT_CHANNEL)public MessageHandler mqttOutbound() {final MqttPahoMessageHandler handler = new MqttPahoMessageHandler(clientId, clientFactory());handler.setDefaultQos(1);handler.setDefaultRetained(false);handler.setDefaultTopic(defaultTopic);handler.setAsync(false);handler.setAsyncEvents(false);return handler;}@Beanpublic MessageChannel mqttInputChannel() {return new DirectChannel();}@Beanpublic MessageProducer inbound() {MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(clientId+"_inbound", clientFactory(), defaultTopic);adapter.setCompletionTimeout(3000);adapter.setConverter(new DefaultPahoMessageConverter());adapter.setQos(1);adapter.setOutputChannel(mqttInputChannel());return adapter;}@Autowiredprivate ApplicationEventPublisher eventPublisher ;@Bean@ServiceActivator(inputChannel = INPUT_CHANNEL)public MessageHandler handler() {return message -> {String topic = Objects.requireNonNull(message.getHeaders().get("mqtt_receivedTopic")).toString();log.info("topic :{} ,payload :{}",topic,message.getPayload().toString());//eventPublisher.publishEvent(new MqttEvent(this, topic, message.getPayload().toString()));};}}

SslUtil.java,读取客户端证书并生成SSLSocketFactory给MQTT连接使用

package com.huali.mec.receiver.util;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PasswordFinder;public class SslUtil {public static SSLSocketFactory getSocketFactory(final String caCrtFile,final String clientCrtFile,final String keyFile,final String password) throws Exception {Security.addProvider(new BouncyCastleProvider());//load ca certificatePEMReader reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(caCrtFile)))));X509Certificate caCert = (X509Certificate)reader.readObject();reader.close();//load client certificatereader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(clientCrtFile)))));X509Certificate clientCert = (X509Certificate)reader.readObject();reader.close();//load client keyreader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFile)))),new PasswordFinder() {@Overridepublic char[] getPassword() {return password.toCharArray();}});KeyPair key = (KeyPair)reader.readObject();reader.close();KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());keyStore.load(null, null);keyStore.setCertificateEntry("ca-certificate", caCert);TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());tmf.init(keyStore);KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());ks.load(null, null);ks.setCertificateEntry("certificate", clientCert);ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(),new java.security.cert.Certificate[] {clientCert});KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());kmf.init(ks,password.toCharArray());SSLContext context = SSLContext.getInstance("TLSv1.2");context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);return context.getSocketFactory();}
}

客户端使用的三个证书文件放到resources/ssl目录下,ca.pem,client.pem,client.key

启动springboot项目,mqttbox客户端发送数据到test这个topic上,这边监听:

控制台打印的消息:

2022-01-21 11:46:12.019  INFO 18368 --- [7785b5b_inbound] c.huali.mec.receiver.config.MqttConfig   : topic :test ,payload :{"id":1,"name":"buejee"}

emqx配置ssl/tsl实现双向认证相关推荐

  1. Centos 7 环境下,如何使用 Apache 实现 SSL 虚拟主机 双向认证 的详细教程:

    1. testing ! ... 1 1 原文参考链接: http://showerlee.blog.51cto.com/2047005/1266712 很久没有更新LAMP的相关文档了,刚好最近单位 ...

  2. ssl证书CA双向认证完整实现步骤(附java客户端代码)(好文章!)

    一.基础概念 注:以下概念除专业名词外,均为个人理解,不具备权威性. 1.什么是系统安全管理 置于公网的系统,通常都需要一定的安全管理,据我个人理解,这里的安全管理主要分三个方面: 一是应用内的权限控 ...

  3. 加密之SSL和单双向认证

    文章目录 1 SSL 1.1 SSL了解 1.2 导入证书 1.3 tomcat配置SSL 1.4 具体操作 2 单向认证 2.1 第三方签名 3 双向认证 3.1 引言 3.2 使用openssl脚 ...

  4. ssl介绍以及双向认证和单向认证原理 (转)

    证书介绍 SSL安全证书可以自己生成,也可以通过第三方的CA(Certification Authority)认证中心付费申请颁发. SSL安全证书包括: 1.       CA证书,也叫根证书或中间 ...

  5. ssl介绍以及双向认证和单向认证原理

    证书介绍 SSL安全证书可以自己生成,也可以通过第三方的CA(Certification Authority)认证中心付费申请颁发. SSL安全证书包括: 1.       CA证书,也叫根证书或中间 ...

  6. SSL单向、双向认证

    引用:http://cbwdkpl.blog.163.com/blog/static/453293822009814111320789/ 单向认证:客户端向服务器发送消息,服务器接到消息后,用服务器端 ...

  7. java代码实现证书生成客户端证书 实现ssl双向认证

    目的:实现web项目的ssl双向认证客户端证书代码生成. 使用openssl生成ca证书和服务端证书,当然也可以通过代码实现 1)创建CA私钥,创建目录ca openssl genrsa -out c ...

  8. c++使用OpenSSL基于socket实现tcp双向认证ssl(使用TSL协议)代码实现

    相信各位对OpenSSL库已经不陌生了,目前笔者使用这个库实现了RSA.AES加解密和tcp的双向认证功能,下面来看tcp的双向认证. 1.什么是双向认证 简单说双向认证就是:客户端认证服务端是否合法 ...

  9. Android本地服务器NanoHttpd配置Https双向认证

    一. 了解数字证书 在HTTPS的传输过程中,有一个非常关键的角色--数字证书,那什么是数字证书?又有什么作用呢? 所谓数字证书,是一种用于电脑的身份识别机制.由数字证书颁发机构(CA)对使用私钥创建 ...

  10. GCDAsyncSOcket使用及其SSL/TLS双向认证的实现

    GCDAsyncSoceket使用及其SSL/TLS的实现 关于GCDAsyncSocket:首先我们得知道GCDAsnyc是由第三方开发的一个苹果系统的socket库,功能强大,而且简单易用.当然关 ...

最新文章

  1. SAP R3 FI 上线 顾问设置教程(一)
  2. 英特尔在网络营销之下即将出现大动作,第二季度服务器出货率将有所提升
  3. php 数据透视表,php – 使用Laravel模型过滤数据透视表数据
  4. 帆软获取上月的第一天与最后一天_《原神》岩港打工第一天怎么玩 岩港打工第一天玩法攻略...
  5. 文件服务器复杂权限,运用技巧:如何提高文件服务器权限?
  6. Linux系统简单实验操作rm
  7. 庄河投资10亿元强力打造“智慧城市”
  8. 对象tostring后怎么转成对象_和女生相亲后怎么联系对方?和相亲对象该如何聊天...
  9. designer pyqt5 界面切换_PyQT5堆叠布局:切换界面(QStackedLayout)
  10. First Kernel-pwn
  11. 双管道(CreatePipe)与cmd.exe进程间通信的有关问题 完美解决
  12. linux重装系统保留文件,linux重装系统,如何保存硬盘中的内容
  13. 经典的图像分割方法总结
  14. Introduction to NLP
  15. 小猪的Python学习之旅 —— 12.Python并发之queue模块
  16. wechall靶场training系列通关记录
  17. 华为p10有java功能吗_华为P10最强悍的特色功能 很多人都不知道
  18. php yii2框架仿站教程,从零开始学YII2框架(六)高级应用程序模板,yii2框架
  19. linux服务开机自启动
  20. Python中%是什么意思?如何使用?

热门文章

  1. 40个科研学术网站,收藏必备,予取予求!
  2. 【ASO项目使用的技术】(例如:1、hook CFUserNotificationCreat 截取Header 部分信息、Message内容 进行任务处理2、设备信息的修改、清理数据3、js逆向)
  3. BurpSuite工具-HTTP协议详解部分(不懂就查系列)
  4. C Minimum Ties
  5. 在讯用矿物质防火电缆时应该注意什么?
  6. 搭建Web服务器建网站的步骤
  7. 计算机毕业设计springboot+vue+elementUI地方废物回收机构管理系统
  8. 谷歌学术搜索技巧,命令搜索
  9. python 3d重建_python三维重建
  10. java计算机毕业设计教师科研成果管理源码+mysql数据库+系统+lw文档+部署