本文描述将使用netty搭建的websokcet服务升级为支持https的wss协议
本文通过2种方式实现
1依赖jdk提供的jks
2依赖签名证书.crt,.key文件实现
JKS
1生成秘钥
keytool -genkey -keysize 2048 -validity 365 -keyalg RSA -keypass netty123 -storepass netty123 -keystore wss.jks
2写一个工具类 构造SSLContext 对象
package com.iptv.rtc.server.netty;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
/**
* @author tq
* @version V1.0
* @Package com.iptv.rtc.server.netty
* @date 2021-04-01 15:49
* @Copyright © 2018-2019 *******
*/
public class SslUtil {
public static SSLContext createSSLContext(String type , String path , String password) throws Exception {
KeyStore ks = KeyStore.getInstance(type); /// "JKS"
InputStream ksInputStream = new FileInputStream(path); /// 证书存放地址
ks.load(ksInputStream, password.toCharArray());
//KeyManagerFactory充当基于密钥内容源的密钥管理器的工厂。
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());//getDefaultAlgorithm:获取默认的 KeyManagerFactory 算法名称。
kmf.init(ks, password.toCharArray());
//SSLContext的实例表示安全套接字协议的实现,它充当用于安全套接字工厂或 SSLEngine 的工厂。
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, null);
return sslContext;
}
}
3将handler放置整个流程第一位
package com.iptv.rtc.server.netty;
import com.iptv.rtc.server.handler.ChatHandler;
import com.iptv.rtc.server.handler.HeartBeatHandler;
import com.iptv.rtc.server.handler.RTCHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
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.SslHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline=socketChannel.pipeline();
SSLContext sslContext = SslUtil.createSSLContext("JKS","/home/iptv/Documents/csr/server.csr","netty123");
//SSLEngine 此类允许使用ssl安全套接层协议进行安全通信
SSLEngine engine = sslContext.createSSLEngine();
engine.setUseClientMode(false);
engine.setNeedClientAuth(false);
pipeline.addLast(new SslHandler(engine));
pipeline.addLast(new HttpServerCodec());
//对大数据流支持
pipeline.addLast(new ChunkedWriteHandler());
//添加对http request和response的支持
pipeline.addLast(new HttpObjectAggregator(1024*64));
//添加ws路由 以及对websocket的 握手 心跳等动作的支持
pipeline.addLast(new WebSocketServerProtocolHandler("/im"));
//自定义handler
pipeline.addLast(new RTCHandler());
//处理心跳断开
// pipeline.addLast(new HeartBeatHandler());
}
}
SSL双向验证
1首先准备好证书以及秘钥文件
server.crt证书文件
server.key秘钥文件
2工具类构造SslContext对象
package com.iptv.rtc.server.netty;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
/**
* @author tq
* @version V1.0
* @Package com.iptv.rtc.server.netty
* @date 2021-04-01 15:49
* @Copyright © 2018-2019 *******
*/
public class SslUtil {
private static final File keyFile = new File("/home/iptv/Documents/csr/server.key");
private static final File rootFile = new File("/home/iptv/Documents/csr/server.crt");
public static SslContext createSSLContext() throws Exception {
SslContext sslCtx = SslContextBuilder.forServer(rootFile, keyFile).clientAuth(ClientAuth.NONE).build();
return sslCtx;
}
}
3添加到流程中的第一位
package com.iptv.rtc.server.netty;
import com.iptv.rtc.server.handler.ChatHandler;
import com.iptv.rtc.server.handler.HeartBeatHandler;
import com.iptv.rtc.server.handler.RTCHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
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.SslHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline=socketChannel.pipeline();
SslContext sslCtx =SslUtil.createSSLContext();
pipeline.addLast(sslCtx.newHandler(socketChannel.alloc()));
pipeline.addLast(new HttpServerCodec());
//对大数据流支持
pipeline.addLast(new ChunkedWriteHandler());
//添加对http request和response的支持
pipeline.addLast(new HttpObjectAggregator(1024*64));
//添加ws路由 以及对websocket的 握手 心跳等动作的支持
pipeline.addLast(new WebSocketServerProtocolHandler("/im"));
//自定义handler
pipeline.addLast(new RTCHandler());
//处理心跳断开
// pipeline.addLast(new HeartBeatHandler());
}
}
有什么问题请大家提出,谢谢
参考:
JKS
https://blog.csdn.net/invadersf/article/details/80337380
https://blog.csdn.net/tiandao321/article/details/91373952
SSL双向
https://segmentfault.com/a/1190000010040134