物联网实战|spring-boot4 + hiveMQ|集成tls
·
- 物联网实战|spring-boot4 + hiveMQ|集成tls
物联网实战|spring-boot4 + hiveMQ|集成tls
源码如下(mqtt-simulator-hivemq-01)
https://gitee.com/kcnf-iot/mqtt-simulator/tree/master/mqtt-simulator-hivemq-01
SAN是什么
- Subject DN(主体名称)
旧标准里,证书域名写在 CN(Common Name,通用名)字段,只能填1 个域名
例:CN=shturl.cc/Y,只能匹配这一个网址
- SAN(主题备用名称)
是 X.509 证书标准扩展字段,可以填写多个域名、IP、主机名,支持:
多个独立域名:a.com、b.com
泛域名:*.shturl.
IP 地址:192.168.1.1、IPv6
本地主机名、邮箱等
问题点
- ca证书转换jks
- spring-boot4开启san强校验问题
ca证书生成
window系统安装openssl
https://slproweb.com/products/Win32OpenSSL.html
将下面命名文件server.cnf,生成ca证书(包含subjectAltName-san)
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = emqx.local
[v3_req]
keyUsage = keyEncipherment, dataEncipherment, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = 127.0.0.1
IP.2 = 192.168.0.20
生成CA私钥(进入openssl目录bin下)
openssl genrsa -out server.key 2048
生成CA证书
openssl req -x509 -new -nodes -key server.key -sha256 -days 3650 -out server.crt -config server.cnf
生成结果

ca证书转换jks
借助keytools(进入jdk目录bin下),将server.crt拷贝过来
keytool -importcert -alias server -file server.crt -keystore truststore.jks -storepass 123456 -noprompt

spring-boot4 + hiveMQ集成
pom依赖
<dependencyManagement>
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>4.0.6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- HiveMQ MQTT5 客户端(同时兼容 MQTT3.1.1) -->
<dependency>
<groupId>com.hivemq</groupId>
<artifactId>hivemq-mqtt-client</artifactId>
<version>1.3.15</version>
</dependency>
代码如下
package com.jysemel.iot;
import com.hivemq.client.mqtt.MqttClientSslConfig;
import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient;
import com.hivemq.client.mqtt.mqtt5.Mqtt5Client;
import com.hivemq.client.mqtt.mqtt5.message.auth.Mqtt5SimpleAuth;
import com.hivemq.client.mqtt.mqtt5.message.connect.Mqtt5Connect;
import javax.net.ssl.TrustManagerFactory;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.UUID;
public class HiveMQTLSClientExample {
private static final String MQTT_HOST = "192.168.0.20";
private static final int MQTT_TLS_PORT = 8085;
private static final String MQTT_USER = "test";
private static final String MQTT_PWD = "123456";
private static final int KEEP_ALIVE = 30;
public static void main(String[] args) {
mqtt5AsyncClient();
}
public static Mqtt5AsyncClient mqtt5AsyncClient() {
// 1. 加载CA根证书,构建SSL信任配置
MqttClientSslConfig sslConfig = buildSslConfig();
// 2. 构建MQTT TLS客户端
String clientId = "server_" + UUID.randomUUID().toString().substring(0, 16);
Mqtt5AsyncClient client = Mqtt5Client.builder()
.identifier(clientId)
.serverHost(MQTT_HOST)
.serverPort(MQTT_TLS_PORT)
.sslConfig(sslConfig)
.buildAsync();
// 3. 构建连接报文
Mqtt5SimpleAuth simpleAuth = Mqtt5SimpleAuth.builder()
.username(MQTT_USER)
.password(MQTT_PWD.getBytes())
.build();
Mqtt5Connect connectMsg = Mqtt5Connect.builder()
.cleanStart(true)
.simpleAuth(simpleAuth)
.keepAlive(KEEP_ALIVE)
.build();
// 4. 发起异步连接
client.connect(connectMsg)
.whenComplete((connAck, throwable) -> {
if (throwable != null) {
throwable.printStackTrace();
System.out.println("MQTT TLS连接失败 ");
return;
}
System.out.println("MQTT TLS连接成功,clientId ");
});
return client;
}
private static MqttClientSslConfig buildSslConfig() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (InputStream is = HiveMQTLSClientExample.class.getResourceAsStream("/cert/emqx.jks")) {
if (is == null) {
throw new RuntimeException("信任库文件未找到: /cert/emqx.jks");
}
String trustStorePassword = "123456";
trustStore.load(is, trustStorePassword.toCharArray());
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
return MqttClientSslConfig.builder()
.trustManagerFactory(tmf)
// 关键:自定义 HostnameVerifier,总是验证通过(仅测试用!)
.hostnameVerifier((hostname, session) -> true)
.build();
} catch (Exception e) {
throw new RuntimeException("SSL 初始化失败", e);
}
}
}
结果如下

如果ca缺失san证书,基于spring-boot4 下面错误
avax.net.ssl.SSLHandshakeException: No subject alternative names present
com.hivemq.client.mqtt.exceptions.ConnectionFailedException: javax.net.ssl.SSLHandshakeException: No subject alternative names present
Caused by: javax.net.ssl.SSLHandshakeException: No subject alternative names present
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:130)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:383)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:326)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321)
at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.check更多推荐

所有评论(0)