netty-写websocket从ws到wss升级

本文描述将使用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

你可能感兴趣的:(JAVA,netty,wss)