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:\security\server>keytool -genkey -alias securechat -keysize 2048 -validity 365 -keyalg RSA -dname "CN=localhost" -keypass sNetty -storepass sNetty -keystore sChat.jks

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

D:\security\server>cd /d ../client

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

D:\security\client>keytool -import -trustcacerts -alias securechat -file ../server\sChat.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服务端源码:

  1. package com.ld.net.spider.server;
  2.  
  3. import io.netty.channel.ChannelHandlerContext;
  4. import io.netty.channel.SimpleChannelInboundHandler;
  5.  
  6. import java.net.InetSocketAddress;
  7.  
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;
  10.  
  11. public class SpiderServerBusiHandler extends SimpleChannelInboundHandler<Object> {
  12. static final Logger logger = LoggerFactory.getLogger(SpiderServerBusiHandler.class);
  13.  
  14. @Override
  15. protected void channelRead0(final ChannelHandlerContext ctx, final Object msg)
  16. throws Exception {
  17. System.out.println(msg.toString());
  18. }
  19.  
  20. @Override
  21. public void exceptionCaught(ChannelHandlerContext ctx,
  22. Throwable cause) throws Exception {
  23. logger.error("channel " + ((InetSocketAddress)ctx.channel().remoteAddress()).toString() + " exception:",cause);
  24. ctx.close();
  25. }
  26. }
  1. package com.ld.net.spider.channel;
  2.  
  3. import java.nio.charset.Charset;
  4.  
  5. import javax.net.ssl.SSLEngine;
  6.  
  7. import com.ld.net.spider.server.SpiderServerBusiHandler;
  8.  
  9. import io.netty.channel.Channel;
  10. import io.netty.channel.ChannelInitializer;
  11. import io.netty.channel.ChannelPipeline;
  12. import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
  13. import io.netty.handler.codec.LengthFieldPrepender;
  14. import io.netty.handler.codec.string.StringDecoder;
  15. import io.netty.handler.codec.string.StringEncoder;
  16. import io.netty.handler.ssl.SslContext;
  17. import io.netty.handler.ssl.SslHandler;
  18.  
  19. public class SslChannelInitializer extends ChannelInitializer<Channel> {
  20. private final SslContext context;
  21.  
  22. public SslChannelInitializer(SslContext context) {
  23. this.context = context;
  24. }
  25.  
  26. @Override
  27. protected void initChannel(Channel ch) throws Exception {
  28. SSLEngine engine = context.newEngine(ch.alloc());
  29. engine.setUseClientMode(false);
  30. ch.pipeline().addFirst("ssl", new SslHandler(engine));
  31. ChannelPipeline pipeline = ch.pipeline();
  32. pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
  33. pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); //最大16M
  34. pipeline.addLast("decoder", new StringDecoder(Charset.forName("UTF-8")));
  35. pipeline.addLast("encoder", new StringEncoder(Charset.forName("UTF-8")));
  36. pipeline.addLast("spiderServerBusiHandler", new SpiderServerBusiHandler());
  37. }
  38. }
  1. package com.ld.net.spider.channel;
  2.  
  3. import io.netty.bootstrap.ServerBootstrap;
  4. import io.netty.buffer.PooledByteBufAllocator;
  5. import io.netty.channel.ChannelOption;
  6. import io.netty.channel.EventLoopGroup;
  7. import io.netty.channel.ServerChannel;
  8. import io.netty.channel.nio.NioEventLoopGroup;
  9. import io.netty.channel.socket.nio.NioServerSocketChannel;
  10. import io.netty.handler.ssl.SslContext;
  11. import io.netty.handler.ssl.SslContextBuilder;
  12.  
  13. import java.io.FileInputStream;
  14. import java.security.KeyStore;
  15.  
  16. import javax.net.ssl.KeyManagerFactory;
  17.  
  18. import org.slf4j.Logger;
  19. import org.slf4j.LoggerFactory;
  20.  
  21. public class SocketServerHelper {
  22. static final Logger logger = LoggerFactory.getLogger(SocketServerHelper.class);
  23. private static int WORKER_GROUP_SIZE = Runtime.getRuntime().availableProcessors() * 2;
  24.  
  25. private static EventLoopGroup bossGroup;
  26. private static EventLoopGroup workerGroup;
  27.  
  28. private static Class<? extends ServerChannel> channelClass;
  29.  
  30. public static void startSpiderServer() throws Exception {
  31. ServerBootstrap b = new ServerBootstrap();
  32. b.childOption(ChannelOption.TCP_NODELAY, true)
  33. .childOption(ChannelOption.SO_KEEPALIVE, true)
  34. .childOption(ChannelOption.SO_REUSEADDR, true)
  35. .childOption(ChannelOption.ALLOCATOR, new PooledByteBufAllocator(false))
  36. .childOption(ChannelOption.SO_RCVBUF, 1048576)
  37. .childOption(ChannelOption.SO_SNDBUF, 1048576);
  38.  
  39. bossGroup = new NioEventLoopGroup(1);
  40. workerGroup = new NioEventLoopGroup(WORKER_GROUP_SIZE);
  41. channelClass = NioServerSocketChannel.class;
  42. logger.info("workerGroup size:" + WORKER_GROUP_SIZE);
  43. logger.info("preparing to start spider server...");
  44. b.group(bossGroup, workerGroup);
  45. b.channel(channelClass);
  46. KeyManagerFactory keyManagerFactory = null;
  47. KeyStore keyStore = KeyStore.getInstance("JKS");
  48. keyStore.load(new FileInputStream("D:\\security\\server\\sChat.jks"), "sNetty".toCharArray());
  49. keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
  50. keyManagerFactory.init(keyStore,"sNetty".toCharArray());
  51. SslContext sslContext = SslContextBuilder.forServer(keyManagerFactory).build();
  52. b.childHandler(new SslChannelInitializer(sslContext));
  53. b.bind(9912).sync();
  54. logger.info("spider server start sucess, listening on port " + 9912 + ".");
  55. }
  56.  
  57. public static void main(String[] args) throws Exception {
  58. SocketServerHelper.startSpiderServer();
  59. }
  60.  
  61. public static void shutdown() {
  62. logger.debug("preparing to shutdown spider server...");
  63. bossGroup.shutdownGracefully();
  64. workerGroup.shutdownGracefully();
  65. logger.debug("spider server is shutdown.");
  66. }
  67. }
  1. package com.ld.net.spider.channel;
  2.  
  3. import java.net.InetSocketAddress;
  4. import java.nio.channels.ClosedChannelException;
  5.  
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8.  
  9. import io.netty.buffer.ByteBuf;
  10. import io.netty.channel.Channel;
  11. import io.netty.channel.ChannelFuture;
  12.  
  13. public class SocketHelper {
  14. static final Logger logger = LoggerFactory.getLogger(SocketHelper.class);
  15.  
  16. public static ChannelFuture writeMessage(Channel channel,String msg) {
  17. if(channel!=null){
  18. try {
  19. return channel.writeAndFlush(msg).sync();
  20. } catch (Exception e) {
  21. String otherInfo = "";
  22.  
  23. if(channel.remoteAddress() != null) {
  24. otherInfo = "remote address [" + ((InetSocketAddress)channel.remoteAddress()).toString() + "]";
  25. } else {
  26. otherInfo = "channel is null.";
  27. }
  28.  
  29. if(e instanceof ClosedChannelException) {
  30. logger.error("channel to " + otherInfo + " is closed",e);
  31. } else {
  32. logger.error("timeout occured during channel send msg, " + otherInfo,e);
  33. }
  34. }
  35. }else{
  36. logger.error("send msg failed, channel is disconnected or not connect. channel is null, please see caller log.");
  37. }
  38. return null;
  39. }
  40.  
  41. public static ChannelFuture writeMessage(Channel channel,ByteBuf msg) {
  42. if(channel!=null){
  43. try {
  44. return channel.writeAndFlush(msg).sync();
  45. } catch (Exception e) {
  46. logger.error("timeout occured during channel send msg. remote address is:" + ((InetSocketAddress)channel.remoteAddress()).toString(),e);
  47. }
  48. }else{
  49. logger.error("send msg failed, channel is disconnected or not connect, channel is null, please see caller log.");
  50. }
  51. return null;
  52. }
  53. }

netty 集成 wss 安全链接的更多相关文章

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

    虽然我们在内部rpc通信中使用的是基于认证和报文头加密的方式实现安全性,但是有些时候仍然需要使用SSL加密,可能是因为对接的三方系统需要,也可能是由于open的考虑.中午特地测了下netty下集成ss ...

  2. 解决gdal集成libkml的链接错误

    作者:朱金灿 来源:http://blog.csdn.net/clever101 gdal库在集成libkml出现一些链接错误: 1>libkmldomD.lib(kml_factory.obj ...

  3. netty集成springboot

    一 前言 springboot 如何集成netty实现mapper调用不为null的问题让好多读者都头疼过,知识追寻者发了一点时间做了个基本入门集成应用给读者们指明条正确的集成方式,我相信,只要你有n ...

  4. Netty集成Protobuf

    一.创建Personproto.proto 创建Personproto.proto文件 syntax = "proto2"; package com.example.protobu ...

  5. 集成bug统计链接

    http://crab.baidu.com/http://bugly.qq.com/ http://bughd.com/ http://www.umeng.com/analyticshttp://tr ...

  6. netty 的 Google protobuf 开发

    根据上一篇博文 Google Protobuf 使用 Java 版 netty 集成 protobuf 的方法非常简单.代码如下: server package protobuf.server.imp ...

  7. Java项目集成SAP BO

    SAP BO报表查看需要登录SAP BO系统,为了方便公司希望将BO报表集成到OA系统中,所以参考网上资料加上与SAP BO的顾问咨询整理出一套通过Java来集成SAP BO的功能. SAPBO中的报 ...

  8. SpringBoot使用Druid数据库加密链接完整方案

    网上的坑 springboot 使用 Druid 数据库加密链接方案,不建议采用网上的一篇文章<springboot 结合 Druid 加密数据库密码遇到的坑!>介绍的方式来进行加密链接实 ...

  9. nginx lua集成kafka

    NGINX lua集成kafka 第一步:进入opresty目录 [root@node03 openresty]# cd /export/servers/openresty/ [root@node03 ...

随机推荐

  1. java第一次考试

    这是我们开学的第一次Java课的考试,考的我有点害怕. 老师说这是给我们在正式上课之前提个醒,确实,我明白了我在学习方面还有多大的差距,确实,就如我高中同学所说的那样,没事就应该往机房跑了. 在上个学 ...

  2. 在oracle中创建自动增长字段

    参考http://www.cnblogs.com/jerrmy/archive/2013/03/13/2958352.html http://www.jb51.net/article/43382.ht ...

  3. 记一次http接口格式摸索

    有一个需求,需要用到内部通讯工具的一个ERP转发接口,虽然有接口文档,但是对中文的编码格式没有提示,中间几经周折,最后才想起来通过F12查看提供的测试接口发送请求时的数据格式来分析,经过解析中文只有被 ...

  4. day4作业(基本运算流程if for)

    #coding:utf-8'''默写: 循环嵌套 必做: 1. 求1-100的所有数的和 2. 输出 1-100 内的所有奇数 3. 输出 1-100 内的所有偶数 5. 求1-2+3-4+5 ... ...

  5. android 开发 实现一个ListView套嵌GirdView的滚动布局

    效果图 实现思维: 首先要处理管理好需要导入的数据,我们这里创建class来处理这些数据并且便于管理它们. 创建一个主activity的布局,里面需要一个ListView控件. 创建一个class继承 ...

  6. scala快速一览

    println("hello world"); val x = +; println(x); //val 不允许再次赋值 //x = 3; //变量var var xx = x; ...

  7. Java序列化对象-字符串转换

    package com.test; import com.alibaba.fastjson.JSON; import org.junit.Test; import java.io.ByteArrayI ...

  8. jquery轮播图片(无插件简单版)

    轮播图(第三版)[2016-2-26] 工作中用的,改写了半透明蒙版,可以兼容ie7 <script type="text/javascript" src="htt ...

  9. Nginx配置HTTPS证书网站

    前提: 1.主机需要先安装openssl     2.编译安装nginx时,要加上--with-http_ssl_module  这个ssl模块 现在开始配置:(我当时配置时,主机已安装了openss ...

  10. python3的命令行参数传递

    #coding:utf-8#命令行参数传递,例如输入: python <文件名>.py -help#这个结果就会打印help#sys.argv[0]代表"文件名",第一 ...