近几年,随着浏览器安全等级的提升,很多地方都要求使用SSL证书来加密连接了。最近因为要开发基于Netty websocket的IM系统,chrome浏览器要求必须使用ssl加密的websocket连接,所以研究了一下怎么给netty配置阿里云的SSL证书。
证书下载、转换
从阿里云下载证书
进入阿里云证书下载页面,如下图。要下载两份,一个是tomcat的,一个是nginx的。
转换证书格式
下载的nginx格式的证书,里面包含pem
和key
两种格式的文件。其中pem
格式我们可以直接用,key
格式的Java无法直接使用。我们使用OpenSSL将前面下载tomcat格式证书pfx
文件转换一个可以使用的key
文件出来。命令如下:
openssl pkcs12 -in coderbbb.com.pfx -nocerts -nodes -out server.key
可能会报错,不过不用管。可以正常使用。
Netty配置SSL证书
netty配置ssl证书其实就是给netty增加了一个ssl的handler。第一步把证书文件读进来,第二步生成一个SSL的handler挂载到netty的handler里。如下图:
完整的代码如下:
package com.coderbbb.blogv2.netty;
import com.coderbbb.blogv2.netty.handler.WebSocketHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
/**
* @author longge93
*/
public class NettyServer {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final int port;
private final SslContext sslContext;
public NettyServer(int port) throws Exception {
this.port = port;
//让netty支持SSL证书
ClassPathResource pem = new ClassPathResource("wss/coderbbb.com.pem");
ClassPathResource key = new ClassPathResource("wss/s.key");
this.sslContext = SslContextBuilder.forServer(pem.getInputStream(), key.getInputStream()).build();
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
.addLast(sslContext.newHandler(ch.alloc()))
//你的自定义Handler
;
}
})
.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
.childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE);
// 绑定端口,开始接收进来的连接
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
解释一下上面加载证书那段代码,使用了ClassPathResource
。这个是Springboot的类,用来从resources目录加载文件的。如果你用的不是springboot,那你直接使用java的File
就可以。new一个file,传入对应位置即可。