• Netty使用SslHandler实现加密通信-双向认证篇


    “不积跬步,无以至千里。”

    说明

    Netty使用SslHandler实现加密通信,认证方式为双向认证,单向认证忽略,话不多说,直接上代码

    引入依赖

    <dependency>
      <groupId>io.nettygroupId>
      <artifactId>netty-allartifactId>
      <version>4.1.100.Finalversion>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    生成keystore.jks文件

    keytool -genkeypair -alias your_alias -keyalg RSA -keystore keystore.jks -keysize 2048
    
    • 1

    Server端

    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.ssl.SslContext;
    import io.netty.handler.ssl.SslContextBuilder;
    import io.netty.handler.ssl.SslProvider;
    import io.netty.util.CharsetUtil;
    
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.TrustManagerFactory;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.nio.charset.StandardCharsets;
    import java.security.KeyStore;
    
    public class NettySslServer {
    
        private static final int PORT = 8888;
    
        public static void main(String[] args) throws Exception {
            // 加载SSL证书
            String serverKeyStorePath = "/home/admin/server/keystore.jks";
            String clientKeyStorePath = "/home/admin/client/keystore.jks";
            String serverKeyStorePassword = "happya";
            String clientKeyStorePassword = "happya";
    
            // 创建SslContext
            KeyStore keyStore = KeyStore.getInstance("JKS");
            try (InputStream keyStoreInputStream = new FileInputStream(serverKeyStorePath)) {
                keyStore.load(keyStoreInputStream, serverKeyStorePassword.toCharArray());
            }
    
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, serverKeyStorePassword.toCharArray());
    
            KeyStore trustStore = KeyStore.getInstance("JKS");
            try (InputStream trustStoreInputStream = new FileInputStream(clientKeyStorePath)) {
                trustStore.load(trustStoreInputStream, clientKeyStorePassword.toCharArray());
            }
    
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(trustStore);
    
            SslContext sslContext = SslContextBuilder.forServer(keyManagerFactory)
                        .trustManager(trustManagerFactory)
                        .sslProvider(SslProvider.OPENSSL)
                        .build();
            // 创建EventLoopGroup
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
    
            try {
                // 创建服务器Bootstrap
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                // 在ChannelPipeline中添加SslHandler
                                pipeline.addLast(sslContext.newHandler(ch.alloc()));
                                // 添加加密通信处理器
                                pipeline.addLast(new SecureChatServerHandler());
                            }
                        })
                        .childOption(ChannelOption.SO_BACKLOG, 128)
                        .childOption(ChannelOption.SO_KEEPALIVE, true);
    
                // 启动服务器
                System.out.println("======Begin to start ssl server======");
                ChannelFuture future = serverBootstrap.bind(PORT).sync();
                System.out.println("======Ssl server started======");
                future.channel().closeFuture().sync();
            } finally {
                workerGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();
            }
        }
    
        public static class SecureChatServerHandler extends ChannelInboundHandlerAdapter {
    
            @Override
            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                // 当连接建立时,发送欢迎消息
                System.out.println("Server channel active : " + ctx.channel().toString());
                ctx.channel().writeAndFlush(Unpooled.wrappedBuffer("Welcome to the secure chat server!\n".getBytes(StandardCharsets.UTF_8)));
                ctx.channel().writeAndFlush(Unpooled.wrappedBuffer("Your connection is protected by SSL.\n".getBytes(StandardCharsets.UTF_8)));
            }
    
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                ByteBuf byteBuf= (ByteBuf) msg;
                System.out.println("Server received message: " + byteBuf.toString(CharsetUtil.UTF_8));
                super.channelRead(ctx, msg);
            }
    
            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                // 处理异常
                cause.printStackTrace();
                ctx.close();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    Client端

    import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import io.netty.handler.ssl.SslContext;
    import io.netty.handler.ssl.SslContextBuilder;
    import io.netty.handler.ssl.SslProvider;
    import io.netty.util.CharsetUtil;
    
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.TrustManagerFactory;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.nio.charset.StandardCharsets;
    import java.security.KeyStore;
    
    public class NettySslClient {
    
        private static final String HOST = "localhost";
        private static final int PORT = 8888;
    
        public static void main(String[] args) throws Exception {
            // 加载SSL证书
            String serverKeyStorePath = "/home/admin/server/keystore.jks";
            String clientKeyStorePath = "/home/admin/client/keystore.jks";
            String serverKeyStorePassword = "happya";
            String clientKeyStorePassword = "happya";
    
            // 创建SslContext
            KeyStore keyStore = KeyStore.getInstance("JKS");
            try (InputStream keyStoreInputStream = new FileInputStream(clientKeyStorePath)) {
                keyStore.load(keyStoreInputStream, clientKeyStorePassword.toCharArray());
            }
    
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, clientKeyStorePassword.toCharArray());
    
            KeyStore trustStore = KeyStore.getInstance("JKS");
            try (InputStream trustStoreInputStream = new FileInputStream(serverKeyStorePath)) {
                trustStore.load(trustStoreInputStream, serverKeyStorePassword.toCharArray());
            }
    
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(trustStore);
    
            // 创建EventLoopGroup
            EventLoopGroup group = new NioEventLoopGroup();
    		SslContext sslContext = SslContextBuilder.forClient()
                        .keyManager(keyManagerFactory)
                        .trustManager(trustManagerFactory)
                        .sslProvider(SslProvider.OPENSSL)
                        .build();
            try {
                // 创建客户端Bootstrap
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(group)
                        .channel(NioSocketChannel.class)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                // 在ChannelPipeline中添加SslHandler
                                pipeline.addLast(sslContext.newHandler(ch.alloc());
                                // 添加加密通信处理器
                                pipeline.addLast(new SecureChatClientHandler());
                            }
                        });
    
                // 连接服务器
                System.out.println("======Begin to start ssl client======");
                ChannelFuture future = bootstrap.connect(HOST, PORT).sync();
                System.out.println("======Ssl client started======");
                future.channel().closeFuture().sync();
            } finally {
                group.shutdownGracefully();
            }
        }
    
        public static class SecureChatClientHandler extends ChannelInboundHandlerAdapter {
    
            @Override
            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                // 连接建立时,发送一条消息给服务器
                System.out.println("Client channel active : " + ctx.channel().toString());
                ctx.channel().writeAndFlush(Unpooled.wrappedBuffer("Hello from client!\n".getBytes(StandardCharsets.UTF_8)));
            }
    
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                ByteBuf byteBuf = (ByteBuf) msg;
                System.out.println("Client received message: \n" + byteBuf.toString(CharsetUtil.UTF_8));
                super.channelRead(ctx, msg);
            }
    
            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                // 处理异常
                cause.printStackTrace();
                ctx.close();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105

    测试结果

    server

    ======Begin to start ssl server======
    ======Ssl server started======
    Server channel active : [id: 0x6cbfa6c6, L:/127.0.0.1:8888 - R:/127.0.0.1:58440]
    Server received message: Hello from client!
    
    • 1
    • 2
    • 3
    • 4

    client

    ======Begin to start ssl client======
    ======Ssl client started======
    Client channel active : [id: 0x9a642804, L:/127.0.0.1:58440 - R:localhost/127.0.0.1:8888]
    Client received message: 
    Welcome to the secure chat server!
    Your connection is protected by SSL.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    分享Bitmap加载Drawable资源失败的解决方法
    【附源码】Python计算机毕业设计社区疫情防控监管系统
    关于射频同轴连接器的功率容量探讨
    MATLAB算法实战应用案例精讲-【神经网络】激活函数:PRelu(附Java、C语言、Python和MATLAB代码)
    STM32 Nucleo-144开发板开箱bring-up
    Java拼图游戏
    使用 Fail2ban 防止 ssh 暴力破解攻击
    lottie 如何停留最后一帧
    实验六 TCP及应用分析
    最新uniApp微信小程序获取头像open-type=“chooseAvatar“ @chooseavatar方法
  • 原文地址:https://blog.csdn.net/Josh_scott/article/details/133890164