Netty服务添加https支持,jdk 证书

1、使用JDK自带的keytool生成一个keystore,这个keystore是服务端使用的,直接在bin目录下执行

keytool -genkey -alias netty -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -keystore D:/test/netty.keystore -storepass 123456

2、新建一个安全工具类,用于返回一个SSLEngine

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import java.security.KeyStore;
import java.security.Security;
/**
 * @description: SSL服务器端认证
 */
public class HttpSslContextFactory {
    private static final Logger LOGGER = LoggerFactory.getLogger(HttpSslContextFactory.class);
//    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) {
            LOGGER.error("初始化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 ;
    }
}

上面的有一个HttpsKeyStore类如下,分别如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

public class HttpsKeyStore {
    private static final Logger LOGGER = LoggerFactory.getLogger(HttpsKeyStore.class);

    /**
     * 读取密钥
     * @version V1.0.0
     * @return InputStream
     */
    public static InputStream getKeyStoreStream() {
        InputStream inStream = null;
        try {
            inStream = new FileInputStream(VarConstant.keystorePath);
        } catch (FileNotFoundException e) {
            LOGGER.error("读取密钥文件失败", e);
        }
        return inStream;
    }

    /**
     * 获取安全证书密码 (用于创建KeyManagerFactory)
     * @version V1.0.0
     * @return char[]
     */
    public static char[] getCertificatePassword() {
        return VarConstant.certificatePassword.toCharArray();
    }

    /**
     * 获取密钥密码(证书别名密码) (用于创建KeyStore)
     * @version V1.0.0
     * @return char[]
     */
    public static char[] getKeyStorePassword() {
        return VarConstant.keystorePassword.toCharArray();
    }
}

其中常量类VarConstant的几个属性如下,其他的不再粘贴:

//SSL
public static Boolean sslEnabled = true;
public static String keystorePath = "D:/test/netty.keystore";
public static String certificatePassword = "123456";
public static String keystorePassword = "123456";

3、上面的步骤做好之后,我们只需给Netty的pipeline的添加第一个的handler,如下:

//是否开启SSL
if (VarConstant.sslEnabled) {
   //务必放在第一位
   ch.pipeline().addLast("sslHandler", new SslHandler(HttpSslContextFactory.createSSLEngine()));
}

4、基本的步骤就是上面这样子,如果要添加双向认证,还需另外生成客户端证书,通过以上这种方式,客户端只需跳过证书认证即可,如使用apache httpclients,跳过认证代码如下:

public static CloseableHttpClient getHttpsClient(){
    SSLContext sslContext = null;
    try {
        //SSLv3或者TLSv1.2都可以
        sslContext = new SSLContextBuilder().useProtocol("TLSv1.2").loadTrustMaterial(null, new TrustStrategy() {
            // 默认信任所有证书
            public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                return true;
            }
        }).build();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    }
    HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,hostnameVerifier);

    SocketConfig socketConfig = SocketConfig.custom()
            .setSoKeepAlive(true)
            .setTcpNoDelay(true)
            .setSoReuseAddress(true)
            .build();
    RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(30000)
            .setSocketTimeout(30000).build();

    HttpClientBuilder clientBuilder = HttpClientBuilder.create();
    return clientBuilder
            .setSSLSocketFactory(sslsf)
            .setDefaultRequestConfig(requestConfig)
            .setDefaultSocketConfig(socketConfig).build();
}

猜你喜欢

转载自blog.csdn.net/qq_41165981/article/details/112366467