zoukankan      html  css  js  c++  java
  • netty 集成 wss 安全链接

    netty集成ssl完整参考指南(含完整源码)

     虽然我们在内部rpc通信中使用的是基于认证和报文头加密的方式实现安全性,但是有些时候仍然需要使用SSL加密,可能是因为对接的三方系统需要,也可能是由于open的考虑。中午特地测了下netty下集成ssl的功能,关于ssl的握手过程以及java安全框架中的相关组件说明,请参考如下链接:

    http://www.cnblogs.com/zhjh256/p/6262620.html

    http://www.cnblogs.com/zhjh256/p/6104537.html

    网上搜了下,并没有看到完整的netty ssl示例例子,netty in action中也只是匆匆带过。特详细的测试和整理如下。

    首先生成服务端证书:

    D:securityserver>keytool -genkey -alias securechat -keysize 2048 -validity 365 -keyalg RSA -dname "CN=localhost" -keypass sNetty -storepass sNetty -keystore sChat.jks

    D:securityserver>keytool -export -alias securechat -keystore sChat.jks -storepass sNetty -file sChat.cer
    存储在文件 <sChat.cer> 中的证书

    D:securityserver>cd /d ../client

    D:securityclient>keytool -genkey -alias smcc -keysize 2048 -validity 365 -keyalg RSA -dname "CN=localhost" -keypass cNetty -storepass cNetty -keystore cChat.jks

    D:securityclient>keytool -import -trustcacerts -alias securechat -file ../serversChat.cer -storepass cNetty -keystore cChat.jks
    所有者: CN=localhost
    发布者: CN=localhost
    序列号: 78384348
    有效期开始日期: Wed Mar 01 12:48:48 CST 2017, 截止日期: Thu Mar 01 12:48:48 CST 2018
    证书指纹:
    MD5: 94:83:6C:6D:4B:0D:0B:E6:BF:39:B7:2C:17:29:E8:3C
    SHA1: 9A:29:27:41:BE:71:38:C8:13:99:3A:8F:C6:37:C2:95:31:14:B4:98
    SHA256: E9:31:40:C7:FC:EA:EF:24:54:EF:4C:59:50:44:CB:1F:9A:35:B7:26:07:2D:3B:1F:BC:30:8E:C0:63:45:4F:21
    签名算法名称: SHA256withRSA
    版本: 3

    扩展:

    #1: ObjectId: 2.5.29.14 Criticality=false
    SubjectKeyIdentifier [
    KeyIdentifier [
    0000: 9B 96 0D 50 4A 5E AF 3D 56 25 9C A5 69 C1 3E CC ...PJ^.=V%..i.>.
    0010: 32 85 0D A8 2...
    ]
    ]

    是否信任此证书? [否]: 是
    证书已添加到密钥库中

    netty服务端源码:

    复制代码
    package com.ld.net.spider.server;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    
    import java.net.InetSocketAddress;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class SpiderServerBusiHandler extends SimpleChannelInboundHandler<Object> {
        static final Logger logger = LoggerFactory.getLogger(SpiderServerBusiHandler.class);
        
        @Override
        protected void channelRead0(final ChannelHandlerContext ctx, final Object msg)
                throws Exception {
            System.out.println(msg.toString());
        }
        
        @Override 
        public void exceptionCaught(ChannelHandlerContext ctx,  
                Throwable cause) throws Exception {  
            logger.error("channel " + ((InetSocketAddress)ctx.channel().remoteAddress()).toString() + " exception:",cause);
            ctx.close();
        }
    }
    复制代码
    复制代码
    package com.ld.net.spider.channel;
    
    import java.nio.charset.Charset;
    
    import javax.net.ssl.SSLEngine;
    
    import com.ld.net.spider.server.SpiderServerBusiHandler;
    
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
    import io.netty.handler.codec.LengthFieldPrepender;
    import io.netty.handler.codec.string.StringDecoder;
    import io.netty.handler.codec.string.StringEncoder;
    import io.netty.handler.ssl.SslContext;
    import io.netty.handler.ssl.SslHandler;
    
    public class SslChannelInitializer extends ChannelInitializer<Channel> {
        private final SslContext context;
    
        public SslChannelInitializer(SslContext context) {
            this.context = context;
        }
    
        @Override
        protected void initChannel(Channel ch) throws Exception {
            SSLEngine engine = context.newEngine(ch.alloc());
            engine.setUseClientMode(false);
            ch.pipeline().addFirst("ssl", new SslHandler(engine));
            ChannelPipeline pipeline = ch.pipeline(); 
            pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));  
            pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));  //最大16M                
            pipeline.addLast("decoder", new StringDecoder(Charset.forName("UTF-8")));  
            pipeline.addLast("encoder", new StringEncoder(Charset.forName("UTF-8")));  
            pipeline.addLast("spiderServerBusiHandler", new SpiderServerBusiHandler());
        }
    }
    复制代码
    复制代码
    package com.ld.net.spider.channel;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.buffer.PooledByteBufAllocator;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.ServerChannel;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.ssl.SslContext;
    import io.netty.handler.ssl.SslContextBuilder;
    
    import java.io.FileInputStream;
    import java.security.KeyStore;
    
    import javax.net.ssl.KeyManagerFactory;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class SocketServerHelper {
        static final Logger logger = LoggerFactory.getLogger(SocketServerHelper.class);
        private static int WORKER_GROUP_SIZE = Runtime.getRuntime().availableProcessors() * 2; 
    
        private static EventLoopGroup bossGroup; 
        private static EventLoopGroup workerGroup;  
        
        private static Class<? extends ServerChannel> channelClass;
        
        public static void startSpiderServer() throws Exception {
            ServerBootstrap b = new ServerBootstrap();
            b.childOption(ChannelOption.TCP_NODELAY, true)
            .childOption(ChannelOption.SO_KEEPALIVE, true)
            .childOption(ChannelOption.SO_REUSEADDR, true)    
            .childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator(false))
            .childOption(ChannelOption.SO_RCVBUF, 1048576)
            .childOption(ChannelOption.SO_SNDBUF, 1048576);
            
            bossGroup = new NioEventLoopGroup(1);
            workerGroup = new NioEventLoopGroup(WORKER_GROUP_SIZE);
            channelClass = NioServerSocketChannel.class;
            logger.info("workerGroup size:" + WORKER_GROUP_SIZE);
            logger.info("preparing to start spider server...");
            b.group(bossGroup, workerGroup);  
            b.channel(channelClass);
            KeyManagerFactory keyManagerFactory = null;
            KeyStore keyStore = KeyStore.getInstance("JKS");
            keyStore.load(new FileInputStream("D:\security\server\sChat.jks"), "sNetty".toCharArray());
            keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
            keyManagerFactory.init(keyStore,"sNetty".toCharArray());
            SslContext sslContext = SslContextBuilder.forServer(keyManagerFactory).build();
            b.childHandler(new SslChannelInitializer(sslContext)); 
            b.bind(9912).sync();  
            logger.info("spider server start sucess, listening on port " + 9912 + ".");  
        }
        
        public static void main(String[] args) throws Exception {
            SocketServerHelper.startSpiderServer();
        }
          
        public static void shutdown() {  
            logger.debug("preparing to shutdown spider server...");
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();  
            logger.debug("spider server is shutdown.");
        }
    }
    复制代码
    复制代码
    package com.ld.net.spider.channel;
    
    import java.net.InetSocketAddress;
    import java.nio.channels.ClosedChannelException;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelFuture;
    
    public class SocketHelper {
        static final Logger logger = LoggerFactory.getLogger(SocketHelper.class);
        
        public static ChannelFuture writeMessage(Channel channel,String msg) {  
            if(channel!=null){  
                try {
                    return channel.writeAndFlush(msg).sync();
                } catch (Exception e) {
                    String otherInfo = "";
                    
                    if(channel.remoteAddress() != null) {
                        otherInfo = "remote address [" + ((InetSocketAddress)channel.remoteAddress()).toString() + "]";
                    } else {
                        otherInfo = "channel is null.";
                    }
                    
                    if(e instanceof ClosedChannelException) {
                        logger.error("channel to " + otherInfo + " is closed",e);
                    } else {
                        logger.error("timeout occured during channel send msg, " + otherInfo,e);
                    }
                }
            }else{
                logger.error("send msg failed, channel is disconnected or not connect. channel is null, please see caller log.");
            }
            return null;
        }
        
        public static ChannelFuture writeMessage(Channel channel,ByteBuf msg) {  
            if(channel!=null){  
                try {
                    return channel.writeAndFlush(msg).sync();
                } catch (Exception e) {
                    logger.error("timeout occured during channel send msg. remote address is:" + ((InetSocketAddress)channel.remoteAddress()).toString(),e);
                }
            }else{
                logger.error("send msg failed, channel is disconnected or not connect, channel is null, please see caller log.");
            }
            return null;
        }
    }
    复制代码
  • 相关阅读:
    使用Selenium对付一个点击游戏
    使用Selenium登录新浪微博
    LeetCode题解 #155 Min Stack
    LeetCode题解 #2 Add Two Numbers
    django for monkey(chapter one)
    Django,数据模型创建之数据库API参考(转载)
    python djang suit模板
    Jmeter多机并发压测IP地址问题
    Jmeter进行数据库压测
    fiddler实现手机端抓包(代理)
  • 原文地址:https://www.cnblogs.com/vana/p/9524428.html
Copyright © 2011-2022 走看看