mqttx工具 使用ca.crt、client.crt、client.key 连接Mqtt 将一下 将图片方式转换为 java代码连接订阅消息
说明 如果在java代码中 使用原有的证书文件连接 会一直报错
因为以上报错 java不能直接读取 ca.crt、client.crt、client.key文件 连接 我们要将三个文件转换为 keystore.jks和truststore.jks文件连接
一、要将 ca.crt、client.crt 和 client.key 转换为 keystore.jks 和 truststore.jks 格式文件,可以按照以下步骤进行:
说明:服务器需要安装 openssl工具 这里就不做详细安装教程了
1 合并客户端证书和私钥:首先,合并客户端证书和私钥到一个 PKCS12 文件中:
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name client-cert -CAfile ca.crt -caname root -chain
这条命令会生成一个名为 client.p12 的 PKCS12 文件。这时候可以输入一个密码输入的密码就是pkcs12password
2 将 PKCS12 文件转换为 keystore.jks 文件:
使用 keytool 将 PKCS12 文件转换为 keystore.jks 文件:
keytool -importkeystore -deststorepass keystorepassword -destkeypass keypassword -destkeystore keystore.jks -srckeystore client.p12 -srcstoretype PKCS12 -srcstorepass pkcs12password -alias client-cert
这条命令会生成一个名为 keystore.jks 的 JKS 文件。
3 将 CA 证书导入到 truststore.jks 文件中:
最后,将 CA 证书导入到 truststore.jks 文件中:
keytool -import -trustcacerts -file ca.crt -alias root-ca -keystore truststore.jks -storepass truststorepassword
在此过程中,如果提示你“是否信任该证书”,输入“yes”并继续。
在上述命令中:
keystorepassword 是 keystore.jks 的密码。
keypassword 是私钥的密码。
pkcs12password 是 client.p12 的密码。
truststorepassword 是 truststore.jks 的密码。
二、编写代码
环境 spirngboot2.6.7 + maven + jdk11
1 配置连接信息放到 yml文件中
spring:
mqtt:
enable: true
url: ssl://ip:端口
username: 用户名
password: 密码
clientId: 客户端唯一id
trustStorePath: 这里我放的是生成truststore.jks文件路径
trustStorePassword: truststore.jks生成时密码(就是第三个命令中trustStorePassword)
keyStorePath: 这里我放的是生成keystore.jks文件路径
keyStorePassword: keystore.jks生成时密码(就是第二个命令中的keypassword)
2导入maven坐标
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
<version>5.5.11</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.47</version>
</dependency>
2 编写代码
2.1 MqttConfig 连接类
package com.anchoremc.cims.mqtt;
import com.anchoremc.cims.util.SslUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* @Author zhongdl
* @Date 2024/5/29 10:21
* @Description: 连接mqq
*/
@Configuration
@Slf4j
public class MqttConfig implements CommandLineRunner {
@Value("${spring.mqtt.enable}")
private Boolean enableFlag;
@Value("${spring.mqtt.url}")
private String hostUrl;
@Value("${spring.mqtt.username}")
private String username;
@Value("${spring.mqtt.password}")
private String password;
@Value("${spring.mqtt.clientId}")
private String clientId;
@Value("${spring.mqtt.trustStorePath}")
private String trustStorePath;
@Value("${spring.mqtt.trustStorePassword}")
private String trustStorePassword;
@Value("${spring.mqtt.keyStorePath}")
private String keyStorePath;
@Value("${spring.mqtt.keyStorePassword}")
private String keyStorePassword;
@Override
public void run(String... args) throws Exception {
//是否启用
if (enableFlag){
//连接mqtt
connect();
}
}
private void connect(){
try {
MqttClient client = new MqttClient(hostUrl, clientId, new MemoryPersistence());
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(username);
options.setPassword(password.toCharArray());
options.setCleanSession(false);
options.setMqttVersion(4);
options.setMqttVersion(3);
options.setSocketFactory(SslUtil.getSocketFactory(trustStorePath,trustStorePassword,keyStorePath,keyStorePassword));
options.setHttpsHostnameVerificationEnabled(false);
// 回调函数
client.setCallback(new MqttCallBack());
client.connect(options);
client.subscribe("UT",0);
log.info(">>>connect success hostUrl:{},clientId:{}",hostUrl,clientId);
} catch (Exception e) {
log.error(">>e",e);
}
}
}
2.2 回调函数
package com.anchoremc.cims.mqtt;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttAsyncClient;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.context.annotation.Configuration;
/**
* @Author zhongdl
* @Date 2024/5/27 17:28
* @Description: mqtt回调
*/
@Configuration
@Slf4j
public class MqttCallBack implements MqttCallback {
/*
* 与服务器断开的回调
*/
@Override
public void connectionLost(Throwable cause) {
log.info("与服务器断开连接:{}",cause);
}
/*
* 消息到达的回调
*/
@Override
public void messageArrived(String topic, MqttMessage message) {
//处理回调逻辑
//订阅携带的数据
byte[] payload = message.getPayload();
log.info(">>>message:{}",message)
}
/*
* 消息发布成功的回调
*/
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
IMqttAsyncClient client = token.getClient();
log.info(client.getClientId() + "发布消息成功!");
}
}
2.3 ssl工具类
package com.anchoremc.cims.util;
import cn.hutool.extra.spring.SpringUtil;
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PasswordFinder;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.X509Certificate;
/**
* @Author zhongdl
* @Date 2024/5/27 18:46
* @Description: SSL工具类
*/
public class SslUtil {
/**
* @Description
* @param: trustStorePath truststore.jks文件路径
* @param: trustStorePassword truststore.jks生成时密码
* @param: keyStorePath keystore.jks文件路径
* @param: keyStorePassword keystore.jks生成时密码
* @Author zhongdl
* @Date 2024/5/27 18:46
*/
public static SSLSocketFactory getSocketFactory(final String trustStorePath,final String trustStorePassword, final String keyStorePath, final String keyStorePassword) throws Exception {
// 加载信任库
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(new FileInputStream(trustStorePath), trustStorePassword.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
// 加载密钥库
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(keyStorePath), keyStorePassword.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyStorePassword.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
return sslContext.getSocketFactory();
}
}
三、测试
启动项目 我们可以 看到**>>>connect success hostUr**l这行日志 就是连接成功 可以发布订阅了