Netty4 TLS单向安全加密传输案例

准备

  • JDK17
  • Netty v4.1.80.Final

🔗原文地址:xilio.cn/post/100

证书生成

采用jdk自带的工具生成。

1、生成服务器密钥库**(server.jks)**

bash 复制代码
keytool -genkeypair -alias serverkey -keyalg RSA -keysize 2048 -storetype JKS -keystore server.jks -dname "CN=localhost" -keypass 123456 -storepass 123456 -validity 3650

2、导出服务器公共证书 (server.cer)

vbscript 复制代码
keytool -exportcert -alias serverkey -keystore server.jks -storepass 123456 -file server.cer

3、创建客户端信任库 (client.truststore) 并导入服务器证书

bash 复制代码
keytool -importcert -alias servercert -file server.cer -keystore client.truststore -storepass 123456 -noprompt

证书上下文创建工厂

java 复制代码
package cn.xilio.netty4.tls.single;
package cn.xilio.netty4.tls.single;

import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.ClientAuth;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;

/**
 * TLS/SSL 上下文工厂,用于创建 Netty 单向认证TLS所需的 SslContext 实例。
 * * 此配置用于客户端验证服务器身份,而服务器不验证客户端身份。
 * 默认使用 JKS 密钥库/信任库格式,并强制启用 TLSv1.3 协议。
 */
public class SslContextFactory {

    private static final String KEYSTORE_PASS = "123456";
    private static final String PROTOCOL_TLS_1_3 = "TLSv1.3";

    // 证书文件路径配置
    private static final File SERVER_KEYSTORE = new File("cert/server.jks");
    private static final File CLIENT_TRUSTSTORE = new File("cert/client.truststore");

    // =========================================================================
    // 核心私有工具方法:加载 JKS 文件并创建工厂
    // =========================================================================

    /**
     * 加载 JKS 密钥库文件并创建 KeyManagerFactory。
     * 用于服务器端,提供私钥和证书链给 SSL/TLS 握手。
     * * @param keyStoreFile JKS 密钥库文件
     *
     * @return KeyManagerFactory 实例
     */
    private static KeyManagerFactory createKeyManagerFactory(File keyStoreFile) throws Exception {
        KeyStore ks = KeyStore.getInstance("JKS");
        try (FileInputStream is = new FileInputStream(keyStoreFile)) {
            ks.load(is, KEYSTORE_PASS.toCharArray());
        }

        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        // 密钥库密码和密钥密码在生成时保持一致
        kmf.init(ks, KEYSTORE_PASS.toCharArray());
        return kmf;
    }

    /**
     * 加载 JKS 信任库文件并创建 TrustManagerFactory。
     * 用于客户端,验证服务器端提供的证书是否可信。
     * * @param trustStoreFile JKS 信任库文件
     *
     * @return TrustManagerFactory 实例
     */
    private static TrustManagerFactory createTrustManagerFactory(File trustStoreFile) throws Exception {
        KeyStore ts = KeyStore.getInstance("JKS");
        try (FileInputStream is = new FileInputStream(trustStoreFile)) {
            ts.load(is, KEYSTORE_PASS.toCharArray());
        }

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ts);
        return tmf;
    }


    // =========================================================================
    // 单向认证TLS上下文创建
    // =========================================================================

    /**
     * 创建单向认证的服务器 SslContext。
     * 服务器提供证书,不要求客户端提供证书 (ClientAuth.NONE)。
     */
    public static SslContext createServerContext() throws Exception {
        System.out.println("【单向认证服务器】加载证书并创建 SslContext...");
        KeyManagerFactory serverKmf = createKeyManagerFactory(SERVER_KEYSTORE);

        return SslContextBuilder
                .forServer(serverKmf)
                .sslProvider(SslProvider.JDK)
                .protocols(PROTOCOL_TLS_1_3)
                .clientAuth(ClientAuth.NONE)
                .build();
    }

    /**
     * 创建单向认证的客户端 SslContext。
     * 客户端信任服务器证书。
     */
    public static SslContext createClientContext() throws Exception {
        System.out.println("【单向认证客户端】加载信任库并创建 SslContext...");
        TrustManagerFactory clientTmf = createTrustManagerFactory(CLIENT_TRUSTSTORE);
        return SslContextBuilder
                .forClient()
                .sslProvider(SslProvider.JDK)
                .protocols(PROTOCOL_TLS_1_3)
                .trustManager(clientTmf)
                .build();
    }
}

服务端

java 复制代码
final SslContext sslContext = SslContextFactory.createServerContext();
//部分代码省略
 protected void initChannel(SocketChannel ch) {
           // 1. SslHandler 必须添加到 Pipeline 的第一个位置
           ch.pipeline().addLast("ssl", sslContext.newHandler(ch.alloc()));
           //其他处理器...
}

客户端

java 复制代码
final SslContext sslContext = SslContextFactory.createClientContext();
//部分代码省略
protected void initChannel(SocketChannel ch) {
         // 1. 创建 SSLEngine,指定主机和端口用于 SNI 和主机名验证
        SSLEngine engine = sslContext.newEngine(ch.alloc(), host, port);
        engine.setUseClientMode(true); // 必须设置为客户端模式
        // 2. SslHandler 必须添加到 Pipeline 的第一个位置
      ch.pipeline().addLast("ssl", new SslHandler(engine));
     //其他处理器...
}

GitHub仓库获取完整代码

相关推荐
hanxiaozhang20182 天前
Netty面试重点-2
面试·netty
9527出列3 天前
Netty源码分析--客户端连接接入流程解析
网络协议·netty
马尚来4 天前
【韩顺平】尚硅谷Netty视频教程
后端·netty
马尚道6 天前
【韩顺平】尚硅谷Netty视频教程
netty
马尚道6 天前
Netty核心技术及源码剖析
源码·netty
moxiaoran57536 天前
java接收小程序发送的protobuf消息
websocket·netty·protobuf
马尚来7 天前
尚硅谷 Netty核心技术及源码剖析 Netty模型 详细版
源码·netty
马尚来7 天前
Netty核心技术及源码剖析
后端·netty
失散1313 天前
分布式专题——35 Netty的使用和常用组件辨析
java·分布式·架构·netty