java连接mqtt订阅消息 使用ssl 证书 ca.crt、client.crt、client.key

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这行日志 就是连接成功 可以发布订阅了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zdl wodeJava

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值