Netty搭建Http2服务端并支持TLS传输加密
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传输加密相关推荐
- Netty在IDEA中搭建HelloWorld服务端并对Netty执行流程与重要组件进行介绍
场景 什么是Netty Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架. Netty 是基于 Java NIO 的异步事件驱动 ...
- 快速搭建Kerberos服务端及入门使用
快速搭建Kerberos服务端及入门使用 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Kerberos是一种网络身份验证协议.它旨在通过使用秘密密钥加密为客户端/服务器应用程序提 ...
- 怎么在Win7服务器搭建SVN服务端
怎么在Win7服务器搭建SVN服务端 今天码大夫给大家分享在Windows服务器上如何搭建SVN环境的详细步骤: 工具/原料 1.VisualSVN server 这是服务器端的安装应用程序,根据自己 ...
- nuxtjs+express+vue2+vuex搭建的服务端渲染(SSR)个人网站项目 1
5se7en.com nuxtjs+express+vue2.0+vuex搭建的服务端渲染个人网站项目. github项目地址: https://github.com/se7en-1992... 项目 ...
- 关于SpringBoot整合Netty客户端和服务端实现JT808协议
关于SpringBoot整合Netty客户端和服务端实现JT808协议 最近做了一个使用netty实现交通部JT808协议的项目,对比了mina和netty两种框架的使用,先整理一下netty的实现过 ...
- 如何在 MacOS 环境下搭建 SVN 服务端环境
文章目录 在服务端创建资源仓库 资源仓库访问权限配置 给资源仓库添加用户 配置用户组及用户的权限 启动 SVN 服务器 停止 SVN 服务器 SVN 是一个使用十分广泛的开放源代码的版本控制系统.在 ...
- linux netty udp服务端,Netty实现UDP服务端
### 前言 在之前的文章我已经讲过了利用`Netty`实现`UDP`客户端,大家有兴趣的话,可以参看下面文章: [Netty实现UDP客户端](https://www.jianshu.com/p/5 ...
- vue.js+koa2项目实战(四)搭建koa2服务端
搭建koa2服务端 安装两个版本的koa 一.版本安装 1.安装 koa1 npm install koa -g 注:必须安装到全局 2.安装 koa2 npm install koa@2 -g 二. ...
- 如何让服务端同时支持WebSocket和SSL加密的WebSocket(即同时支持ws和wss)?
自从HTML5出来以后,使用WebSocket通信就变得火热起来,基于WebSocket开发的手机APP和手机游戏也越来越多.我的一些开发APP的朋友,开始使用WebSocket通信,后来觉得通信 ...
最新文章
- 安全狗php站点404,访问编码后的中文URL返回404错误的解决方法
- LB 负载均衡的层次结构
- iOS实现自定义的弹出视图(popView)
- python教程:os.chdir() 基本用法
- Java导出数据到Excel
- 【小松教你手游开发】【游戏渲染】单色shader,纹理shader
- conduit 安装试用
- 长字符串显示引起的问题通用性解决方法
- forge不能用java打开_minecraft萌新官方启动器、forge、java常见问题
- Slate轨道工具使用(二)—Odin支持
- Python检测和防御DOS攻击
- 高级计量经济学及Stata应用 第2版_陈强
- LeetCode:934. Shortest Bridge - Python
- 【csdn学习-Python】CSDN技能树-Python语言学习笔记
- c语言如何让正数带负号
- win10开启hdr功能屏幕泛白如何解决?
- 2019广东工业智造创新大赛【赛场二】感谢拼命的自己
- 【花雕动手做】有趣好玩的音乐可视化系列小项目(19)--通体光纤灯
- 37互娱java待遇,37互娱现场java一面
- R语言Bioconductor安装全流程
热门文章
- redis通过key模糊搜索_Redis几个实战经验积累
- 实验一 熟悉上机环境及顺序、选择结构程序设计
- 最新防雷检测收费项目和收费标准河南万佳防雷检测验收
- python 进行各种回归
- DWDM的原理以及其系统应用
- 这样使用Node.js压缩PNG图片,效果高达75%
- 全球低轨卫星物联网的发展现状
- 室内场景三维对象分割(Ransac+supervoxel dbscan+guided filter)
- c++ 队列_Day 5:用两个栈实现队列
- html 页面滚动时 div位置不变,js实现页面刷新滚动条位置不变