Netty搭建Http2服务端并支持TLS传输加密

@Slf4j
public class SslUtil {public static SslContext sslContext() {SslProvider provider = SslProvider.isAlpnSupported(SslProvider.OPENSSL) ? SslProvider.OPENSSL : SslProvider.JDK;log.info("provider:{}", provider);SelfSignedCertificate ssc = null;try {ssc = new SelfSignedCertificate();} catch (CertificateException e) {throw new RuntimeException(e);}ApplicationProtocolConfig applicationProtocolConfig = new ApplicationProtocolConfig(ApplicationProtocolConfig.Protocol.ALPN,ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,ApplicationProtocolNames.HTTP_2,ApplicationProtocolNames.HTTP_1_1);SslContext sslContext = null;try {sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).sslProvider(provider).ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE).applicationProtocolConfig(applicationProtocolConfig).build();} catch (SSLException e) {throw new RuntimeException(e);}return sslContext;}}

注意:io.netty.handler.ssl.util.SelfSignedCertificate 只用于测试,不要用于生产环境!!!

public class Http2ServerResponseHandler extends ChannelDuplexHandler {static final ByteBuf RESPONSE_BYTES = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8));@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {if (msg instanceof Http2HeadersFrame) {Http2HeadersFrame msgHeader = (Http2HeadersFrame) msg;if (msgHeader.isEndStream()) {ByteBuf content = ctx.alloc().buffer();content.writeBytes(RESPONSE_BYTES.duplicate());Http2Headers headers = new DefaultHttp2Headers().status(HttpResponseStatus.OK.codeAsText());ctx.write(new DefaultHttp2HeadersFrame(headers).stream(msgHeader.stream()));ctx.write(new DefaultHttp2DataFrame(content, true).stream(msgHeader.stream()));}} else {super.channelRead(ctx, msg);}}}
/*** Created by bruce on 2021/12/10 15:13*/
@Slf4j
public class Http2Server {private NioEventLoopGroup bossGroup;private NioEventLoopGroup workerGroup;public synchronized void start(int port) {bossGroup = new NioEventLoopGroup(1);workerGroup = new NioEventLoopGroup();try {ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.option(ChannelOption.SO_BACKLOG, 1024).group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new Http2ServerInitializer());//ChannelFuture channelFuture = bootstrap.bind(port).sync();log.info("http2 server started on port:{}", port);} catch (Exception e) {log.error("Http2ServerBootstrap-->", e);close();}}public static class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel channel) throws Exception {ChannelPipeline pipeline = channel.pipeline();SslHandler sslHandler = SslUtil.sslContext().newHandler(channel.alloc());pipeline.addLast("sslHandler", sslHandler);pipeline.addLast("applicationProtocolNegotiationHandler", new MyAppProtocolNegotiationHandler());}}//根据请求的协议添加对应的处理器public static class MyAppProtocolNegotiationHandler extends ApplicationProtocolNegotiationHandler {public MyAppProtocolNegotiationHandler() {super(ApplicationProtocolNames.HTTP_2);}protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {Http2FrameCodec http2FrameCodec = Http2FrameCodecBuilder.forServer().build();ctx.pipeline().addLast(http2FrameCodec);ctx.pipeline().addLast(new Http2ServerResponseHandler());} else {throw new IllegalStateException("Protocol: " + protocol + " not supported");}}}public synchronized void close() {if (bossGroup != null) {bossGroup.shutdownGracefully();}if (workerGroup != null) {workerGroup.shutdownGracefully();}log.info("destroy netty server thread");}}
public static void main(String[] args) {Http2Server http2Server = new Http2Server();http2Server.start(8443);
}

测试http2服务

curl -k -v --http2 https://127.0.0.1:8443

测试http1.1服务

curl -k -v --http1.1 https://127.0.0.1:8443

使用 jdk 提供的SslProvider

使用jdk提供的SslProvider,但是jdk8不支持ALPN,出现如下异常,只能使用高版本的jdk。

示例使用的是jdk17可以支持ALPN,但是运行时会出现如下异常

Caused by: java.security.cert.CertificateException: No provider succeeded to generate a self-signed certificate. See debug log for the root cause.at io.netty.handler.ssl.util.SelfSignedCertificate.<init>(SelfSignedCertificate.java:249) ~[netty-handler-4.1.70.Final.jar:4.1.70.Final]at io.netty.handler.ssl.util.SelfSignedCertificate.<init>(SelfSignedCertificate.java:166) ~[netty-handler-4.1.70.Final.jar:4.1.70.Final]at io.netty.handler.ssl.util.SelfSignedCertificate.<init>(SelfSignedCertificate.java:115) ~[netty-handler-4.1.70.Final.jar:4.1.70.Final]at io.netty.handler.ssl.util.SelfSignedCertificate.<init>(SelfSignedCertificate.java:90) ~[netty-handler-4.1.70.Final.jar:4.1.70.Final]at com.bruce.netty.http2.handler.SslUtil.sslContext(SslUtil.java:24) ~[classes/:na]... 21 common frames omittedSuppressed: java.lang.NoClassDefFoundError: org/bouncycastle/jce/provider/BouncyCastleProviderat io.netty.handler.ssl.util.BouncyCastleSelfSignedCertGenerator.<clinit>(BouncyCastleSelfSignedCertGenerator.java:43) ~[netty-handler-4.1.70.Final.jar:4.1.70.Final]at io.netty.handler.ssl.util.SelfSignedCertificate.<init>(SelfSignedCertificate.java:240) ~[netty-handler-4.1.70.Final.jar:4.1.70.Final]... 25 common frames omittedCaused by: java.lang.ClassNotFoundException: org.bouncycastle.jce.provider.BouncyCastleProviderat java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)... 27 common frames omitted
Caused by: java.lang.IllegalAccessError: class io.netty.handler.ssl.util.OpenJdkSelfSignedCertGenerator (in unnamed module @0x5e316c74) cannot access class sun.security.x509.X509CertInfo (in module java.base) because module java.base does not export sun.security.x509 to unnamed module @0x5e316c74at io.netty.handler.ssl.util.OpenJdkSelfSignedCertGenerator.generate(OpenJdkSelfSignedCertGenerator.java:52) ~[netty-handler-4.1.70.Final.jar:4.1.70.Final]at io.netty.handler.ssl.util.SelfSignedCertificate.<init>(SelfSignedCertificate.java:246) ~[netty-handler-4.1.70.Final.jar:4.1.70.Final]... 25 common frames omitted

该问题乍一看以为是缺少org.bouncycastle.jce.provider.BouncyCastleProvider导致的异常,当添加了如下依赖后确实也可以解决问题。

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcpkix-jdk15on</artifactId><version>1.70</version>
</dependency>

但实际原因并不是缺少该依赖导致的,看最后一个Caused by:
because module java.base does not export sun.security.x509 to unnamed module @0x5e316c74

实际原因:jdk17因为模块化并没有在 java.base中导出sun.security.x509包,没有权限访问sun.security.x509.X509CertInfo导致无法实例化。

解决办法:不需要org.bouncycastle:bcpkix-jdk15on依赖,在启动时添加如下参数即可

--add-opens java.base/sun.security.x509=ALL-UNNAMED

使用OPENSSL提供的SslProvider

添加如下依赖依赖,OPENSSL不需要依赖jdk提供了ALPN支持,因此在jdk8,jdk17上同样可以运行。

<dependency><groupId>io.netty</groupId><artifactId>netty-tcnative-boringssl-static</artifactId>
</dependency>

当切换到jdk17时,再次执行则会出现上面所提到的异常,具体原因及解决方案上面已经说明

Caused by: java.lang.IllegalAccessError: class io.netty.handler.ssl.util.OpenJdkSelfSignedCertGenerator (in unnamed module @0x5e316c74) cannot access class sun.security.x509.X509CertInfo (in module java.base) because module java.base does not export sun.security.x509 to unnamed module @0x5e316c74at io.netty.handler.ssl.util.OpenJdkSelfSignedCertGenerator.generate(OpenJdkSelfSignedCertGenerator.java:52) ~[netty-handler-4.1.70.Final.jar:4.1.70.Final]at io.netty.handler.ssl.util.SelfSignedCertificate.<init>(SelfSignedCertificate.java:246) ~[netty-handler-4.1.70.Final.jar:4.1.70.Final]... 25 common frames omitted

但为什么加了org.bouncycastle:bcpkix-jdk15on依赖同样可以解决问题呢?
源码见:io.netty.handler.ssl.util.SelfSignedCertificate#SelfSignedCertificate(String, java.security.SecureRandom, int, Date, Date, String)
原因是Netty优先使用的使用Bouncy Castle生成自签名证书。当不存在时再使用OpenJDK提供的sun.security.x509生成自签名证书。所以使用Bouncy Castle之后就不会走到下面逻辑,不会访问创建X509CertInfo对象,所以正常执行.

Netty搭建Http2服务端并支持TLS传输加密相关推荐

  1. Netty在IDEA中搭建HelloWorld服务端并对Netty执行流程与重要组件进行介绍

    场景 什么是Netty Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架. Netty 是基于 Java NIO 的异步事件驱动 ...

  2. 快速搭建Kerberos服务端及入门使用

    快速搭建Kerberos服务端及入门使用 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Kerberos是一种网络身份验证协议.它旨在通过使用秘密密钥加密为客户端/服务器应用程序提 ...

  3. 怎么在Win7服务器搭建SVN服务端

    怎么在Win7服务器搭建SVN服务端 今天码大夫给大家分享在Windows服务器上如何搭建SVN环境的详细步骤: 工具/原料 1.VisualSVN server 这是服务器端的安装应用程序,根据自己 ...

  4. nuxtjs+express+vue2+vuex搭建的服务端渲染(SSR)个人网站项目 1

    5se7en.com nuxtjs+express+vue2.0+vuex搭建的服务端渲染个人网站项目. github项目地址: https://github.com/se7en-1992... 项目 ...

  5. 关于SpringBoot整合Netty客户端和服务端实现JT808协议

    关于SpringBoot整合Netty客户端和服务端实现JT808协议 最近做了一个使用netty实现交通部JT808协议的项目,对比了mina和netty两种框架的使用,先整理一下netty的实现过 ...

  6. 如何在 MacOS 环境下搭建 SVN 服务端环境

    文章目录 在服务端创建资源仓库 资源仓库访问权限配置 给资源仓库添加用户 配置用户组及用户的权限 启动 SVN 服务器 停止 SVN 服务器 SVN 是一个使用十分广泛的开放源代码的版本控制系统.在 ...

  7. linux netty udp服务端,Netty实现UDP服务端

    ### 前言 在之前的文章我已经讲过了利用`Netty`实现`UDP`客户端,大家有兴趣的话,可以参看下面文章: [Netty实现UDP客户端](https://www.jianshu.com/p/5 ...

  8. vue.js+koa2项目实战(四)搭建koa2服务端

    搭建koa2服务端 安装两个版本的koa 一.版本安装 1.安装 koa1 npm install koa -g 注:必须安装到全局 2.安装 koa2 npm install koa@2 -g 二. ...

  9. 如何让服务端同时支持WebSocket和SSL加密的WebSocket(即同时支持ws和wss)?

      自从HTML5出来以后,使用WebSocket通信就变得火热起来,基于WebSocket开发的手机APP和手机游戏也越来越多.我的一些开发APP的朋友,开始使用WebSocket通信,后来觉得通信 ...

最新文章

  1. 安全狗php站点404,访问编码后的中文URL返回404错误的解决方法
  2. LB 负载均衡的层次结构
  3. iOS实现自定义的弹出视图(popView)
  4. python教程:os.chdir() 基本用法
  5. Java导出数据到Excel
  6. 【小松教你手游开发】【游戏渲染】单色shader,纹理shader
  7. conduit 安装试用
  8. 长字符串显示引起的问题通用性解决方法
  9. forge不能用java打开_minecraft萌新官方启动器、forge、java常见问题
  10. Slate轨道工具使用(二)—Odin支持
  11. Python检测和防御DOS攻击
  12. 高级计量经济学及Stata应用 第2版_陈强
  13. LeetCode:934. Shortest Bridge - Python
  14. 【csdn学习-Python】CSDN技能树-Python语言学习笔记
  15. c语言如何让正数带负号
  16. win10开启hdr功能屏幕泛白如何解决?
  17. 2019广东工业智造创新大赛【赛场二】感谢拼命的自己
  18. 【花雕动手做】有趣好玩的音乐可视化系列小项目(19)--通体光纤灯
  19. 37互娱java待遇,37互娱现场java一面
  20. R语言Bioconductor安装全流程

热门文章

  1. redis通过key模糊搜索_Redis几个实战经验积累
  2. 实验一 熟悉上机环境及顺序、选择结构程序设计
  3. 最新防雷检测收费项目和收费标准河南万佳防雷检测验收
  4. python 进行各种回归
  5. DWDM的原理以及其系统应用
  6. 这样使用Node.js压缩PNG图片,效果高达75%
  7. 全球低轨卫星物联网的发展现状
  8. 室内场景三维对象分割(Ransac+supervoxel dbscan+guided filter)
  9. c++ 队列_Day 5:用两个栈实现队列
  10. html 页面滚动时 div位置不变,js实现页面刷新滚动条位置不变