zoukankan      html  css  js  c++  java
  • Netty ssl双向认证

    生成证书及代码中有关密码的操作,请按照你们自己的需要修改成自己的

    使用keytool生成证书

    这个命令一般在JDKjrelibsecurity目录下操作

    keytool常用命令

    参数 释义
    -alias 证书的别名
    -keystore 证书库的名称
    -storepass 证书库的密码
    -keypass 证书的密码
    -list 显示密钥库中的证书信息
    -v 显示密钥库中的证书详细信息
    -export 显示密钥库中的证书信息
    -file 指定导出证书的文件名和路径
    -delete 删除密钥库中某条目
    -import 将已签名数字证书导入密钥库
    -keypasswd 修改密钥库中指定条目口令
    -dname 指定证书拥有者信息
    -keyalg 指定密钥的算法
    -validity 指定创建的证书有效期多少天
    -keysize 指定密钥长度

    具体生成证书操作

    1. 创建服务端秘钥
    keytool -genkey -alias nettyServer -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=localhost" -keypass 证书密码 -storepass 服务端的证书仓库密码 -keystore serverCerts.jks
    
    1. 导出服务端秘钥
    keytool -export -alias nettyServer -keystore serverCerts.jks -storepass 服务端的证书仓库密码 -file serverCert.cer
    
    1. 创建客户端秘钥
    keytool -genkey -alias nettyClient -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=PF,OU=YJC,O=YJC,L=BJ,S=BJ,C=ZN" -keypass 证书密码 -storepass 客户端的证书仓库密码 -keystore clientCerts.jks
    
    1. 导出客户端秘钥
    keytool -export -alias nettyClient -keystore clientCerts.jks -file nettyclientCert.cer -storepass 客户端的证书仓库密码
    
    1. 将客户端的证书导入到服务端的信任证书仓库中
    keytool -import -trustcacerts -alias smcc -file nettyClientCert.cer -storepass 服务端的证书仓库密码 -keystore serverCerts.jks
    
    1. 将服务端的证书导入到客户端的信任证书仓库中
    keytool -import -trustcacerts -alias smccClient -file serverCert.cer -storepass 客户端的证书仓库密码 -keystore clientCerts.jks
    

    服务端创建ContextSSLFactory

    package com.yjc.rpc.ssl;
    
    
    import org.springframework.core.io.ClassPathResource;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.security.KeyStore;
    import java.security.NoSuchAlgorithmException;
    
    import javax.net.ssl.*;
    
    
    public class ContextSSLFactory {
    
        private static final SSLContext SSL_CONTEXT_S ;
    
        static{
            SSLContext sslContextServer = null ;
            try {
                sslContextServer = SSLContext.getInstance("SSLv3") ;
    
            } catch (NoSuchAlgorithmException e1) {
                e1.printStackTrace();
            }
            try{
                if(getKeyManagersServer() != null && getTrustManagersServer() != null ){
                    sslContextServer.init(getKeyManagersServer(), getTrustManagersServer(), null);
                }
    
    
            }catch(Exception e){
                e.printStackTrace() ;
            }
            sslContextServer.createSSLEngine().getSupportedCipherSuites() ;
            SSL_CONTEXT_S = sslContextServer ;
        }
        public ContextSSLFactory(){
    
        }
        public static SSLContext getSslContext(){
            return SSL_CONTEXT_S ;
        }
        /**
         * 获取服务端信任的证书
         * @param:             @return
         * @return:         TrustManager[]
         * @throws
         */
        private static TrustManager[] getTrustManagersServer(){
            FileInputStream is = null ;
            TrustManager[] trustManagersw=null;
            TrustManagerFactory trustManagerFactory=null;
            KeyStore ks=null;
            try {
                trustManagerFactory = TrustManagerFactory.getInstance("SunX509") ;
                is =is =new FileInputStream( (new ClassPathResource("certs/serverCerts.jks")).getFile() );
                String keyStorePass = "服务端的证书仓库密码" ;
    			ks=KeyStore.getInstance("JKS");
    			ks.load(is,keyStorePass.toCharArray());
                trustManagerFactory.init(ks);
                trustManagersw=trustManagerFactory.getTrustManagers();
            } catch (Exception e) {
                e.printStackTrace();
            }
            finally{
                if(is != null ){
                    try {
                        is.close() ;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return trustManagersw;
        }
    
    
        /**
         * 获取keymanager列表
         * @param:             @return
         * @return:         KeyManager[]
         * @throws
         */
        private static KeyManager[] getKeyManagersServer(){
            FileInputStream is = null ;
            KeyStore ks = null ;
            KeyManagerFactory keyFac = null ;
    
            KeyManager[] kms = null ;
            try {
                // 获得KeyManagerFactory对象. 初始化位默认算法
                keyFac = KeyManagerFactory.getInstance("SunX509") ;
    //            String keyStorePath = PropertyUtil.getProperty("httpsKeyStorePath");
                is =new FileInputStream( (new ClassPathResource("certs/serverCerts.jks")).getFile() );
                ks = KeyStore.getInstance("JKS") ;
                String keyStorePass = "服务端的证书仓库密码";
                ks.load(is , keyStorePass.toCharArray()) ;
                keyFac.init(ks, keyStorePass.toCharArray()) ;
                kms = keyFac.getKeyManagers() ;
            } catch (Exception e) {
                e.printStackTrace();
            }
            finally{
                if(is != null ){
                    try {
                        is.close() ;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return kms ;
        }
    }
    
    

    在pipeline中添加netty自带的sslHandler

    这里需要注意的是 SslHandler需要添加到pipeline的最前面,否则即使加上了,不合法的客户端一样可以正常连接

       try {
                //设置事件处理
                serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ChannelPipeline pipeline = ch.pipeline();
                        // 添加心跳支持
                        pipeline.addLast(new IdleStateHandler(5, 0, 0, TimeUnit.SECONDS));
                        // 基于定长的方式解决粘包/拆包问题
    //                    pipeline.addLast(new LengthFieldBasedFrameDecoder(nettyConfig.getMaxFrameLength()
    //                            , 0, 2, 0, 2));
    //                    pipeline.addLast(new LengthFieldPrepender(2));
                        // 序列化
    //                    pipeline.addLast(new MessagePackDecoder());
    //                    pipeline.addLast(new MessagePackEncoder());
                        pipeline.addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
                        pipeline.addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
                        pipeline.addLast(channelHandlerAdapter);
                        SSLEngine engine = ContextSSLFactory.getSslContext().createSSLEngine();
                        engine.setUseClientMode(false); //设置为服务端模式
                        engine.setNeedClientAuth(true); //需要验证客户端
                        pipeline.addFirst("ssl", new SslHandler(engine));   //这个handler需要加到最前面
                    }
                });
                LOGGER.info("netty服务器在[{}]端口启动监听", port);
                ChannelFuture f = serverBootstrap.bind(port).sync();
                f.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                LOGGER.info("[出现异常] 释放资源");
                boss.shutdownGracefully();
                work.shutdownGracefully();
            }
    

    客户端代码基本是类似的,这里就不贴了。

  • 相关阅读:
    MATLAB 编程风格指南及注意事项
    Redis笔记
    HDU-5706
    【sqli-labs】 less4 GET
    【sqli-labs】 less3 GET
    【sqli-labs】 less2 GET
    【sqli-labs】 less1 GET
    Ubuntu14.04环境下java web运行环境搭建
    Android进度条控件ProgressBar使用
    Android中DatePicker与TimePicker用法讲解(包括DatePickerDialog与TimePickerDialog)
  • 原文地址:https://www.cnblogs.com/falcon-fei/p/11453727.html
Copyright © 2011-2022 走看看