各种新的规范出现,因此基础需求也得更新换代。
在使用https与wss前,需要了解几个东西:
1.服务器ssl证书,这个商用都需要到正规平台去申请。开发阶段可以用相关工具创建测试用的证书供服务器使用。这里我用的是java的keytools来创建的。
命令如下:
keytool -genkey -alias netty -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -keystore D:/test.keystore -storepass 123456
正式开发时,申请的证书可能是.pem格式的,实际上格式有好多种。这里一般都需要各种转换操作。
如果jdk没有配置到环境变量,那么需要手动找到keytool.exe,在jdk或者jre中的bin出都有,使用cmd,一层层进入到bin文件中,然后使用上面的命令即可。
常见操作:https://www.jianshu.com/p/a493a6380c23
2.netty中加入ssl证书操作:https
package testHttps1;
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.HttpServerCodec;
import io.netty.handler.ssl.SslHandler;
public class httpsServer {
private int port;
public httpsServer(int port) {
this.port = port;
}
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() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
//注意要放在第一位
ch.pipeline().addLast("sslHandler", new SslHandler(HttpSslContextFactory.createSSLEngine()));
ch.pipeline().addLast("http-decoder", new HttpServerCodec());
ch.pipeline().addLast(new httpsServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind(port).sync();
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 10001;
}
new httpsServer(port).run();
}
}
package testHttps1;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
public class httpsServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof HttpRequest) {
HttpRequest request = (HttpRequest) msg;
boolean keepaLive = HttpUtil.isKeepAlive(request);
System.out.println("method:" + request.method());
System.out.println("uri:" + request.uri());
FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
httpResponse.content().writeBytes("https".getBytes());
httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=UTF-8");
httpResponse.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, httpResponse.content().readableBytes());
if (keepaLive) {
httpResponse.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
ctx.writeAndFlush(httpResponse);
} else {
ctx.writeAndFlush(httpResponse).addListener(ChannelFutureListener.CLOSE);
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
package testHttps1;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import java.security.KeyStore;
import java.security.Security;
public class HttpSslContextFactory {
// private static final String PROTOCOL = "SSLv2";
private static final String PROTOCOL = "SSLv3";//客户端可以指明为SSLv3或者TLSv1.2
/**针对于服务器端配置*/
private static SSLContext sslContext = null;
static {
String algorithm = Security
.getProperty("ssl.KeyManagerFactory.algorithm");
if (algorithm == null) {
algorithm = "SunX509";
}
SSLContext serverContext = null;
try {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(HttpsKeyStore.getKeyStoreStream(), HttpsKeyStore.getKeyStorePassword());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
kmf.init(ks, HttpsKeyStore.getCertificatePassword());
serverContext = SSLContext.getInstance(PROTOCOL);
serverContext.init(kmf.getKeyManagers(), null, null);
} catch (Exception e) {
System.out.println("初始化server SSL失败 "+ e);
throw new Error("Failed to initialize the server SSLContext", e);
}
sslContext = serverContext;
}
public static SSLEngine createSSLEngine() {
SSLEngine sslEngine = sslContext.createSSLEngine();
sslEngine.setUseClientMode(false);
sslEngine.setNeedClientAuth(false);
return sslEngine ;
}
}
package testHttps1;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class HttpsKeyStore {
public static InputStream getKeyStoreStream() {
InputStream inStream = null;
try {
inStream = new FileInputStream(Arguments.keystorePath);
} catch (FileNotFoundException e) {
System.out.println("读取密钥文件失败 "+ e);
}
return inStream;
}
public static char[] getCertificatePassword() {
return Arguments.certificatePassword.toCharArray();
}
public static char[] getKeyStorePassword() {
return Arguments.keystorePassword.toCharArray();
}
}
package testHttps1;
public class Arguments {
public static String keystorePath = "D:/test.keystore";
public static String certificatePassword = "123456";
public static String keystorePassword = "123456";
}
3.对于wss 也只需要加入ch.pipeline().addLast("sslHandler", new SslHandler(HttpSslContextFactory.createSSLEngine()));相关处理即可。