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. redis参数改进建议

    1.修改stop-writes-on-bgsave-error为no当前配置为yes,分别修改redis.conf和当前实例#redis.confstop-writes-on-bgsave-error ...

  2. Java课程作业之动手动脑(五)

    1.请阅读并运行AboutException.java示例. import javax.swing.*; class AboutException { public static void main( ...

  3. python中import和from-import的区别

    . import导入模块的路径两种方式 # 将模块所在路径再程序中添加到sys.path列表中 import sys sys.path import导入模块按照sys.path顺序依次查找,“”代表当 ...

  4. 浏览器预览office文件(word,Excel,等)

    提示:预览是通过后台转pdf到前台展示的过程,当然网上也有购买的api 举个栗子:(http://www.officeweb365.com/) <!DOCTYPE html> <ht ...

  5. ROS进阶学习手记 7 -- RViz仿真实例1

    [任务2]:     用simulator: RViz 工具,完成对小车的建模,名字drive RViz = dvrv, 用 dvrv_node 发布topic和数据格式,向它发送位置指令,使它能接受 ...

  6. laravel 的 intervention-image 图像处理笔记

    安装: https://blog.csdn.net/beyond__devil/article/details/62230610 需求: PHP >= 5.4 Fileinfo 扩展 GD库 & ...

  7. LinkedHashMap结构get和put源码流程简析及LRU应用

    原理这篇讲得比较透彻Java集合之LinkedHashMap. 本文属于源码阅读笔记,因put,get调用逻辑及链表维护逻辑复杂(至少网上其它文章的逻辑描述及配图,我都没看明白LinkedHashMa ...

  8. JS call和apply方法使用

    总是对call和apply方法使用存在迷惑,特此记录一下 一句话理解这两个方法: call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call ...

  9. Dubbo 服务容错Hystrix

    一.服务者 1.pom <dependency> <groupId>org.springframework.cloud</groupId> <artifact ...

  10. vue-x action 的相互调用

    实现方式:分发 Action Action 通过 store.dispatch 方法触发: store.dispatch('increment')