生成证书及代码中有关密码的操做,请按照大家本身的须要修改为本身的java
这个命令通常在JDK\jre\lib\security\目录下操做算法
参数 | 释义 |
---|---|
-alias | 证书的别名 |
-keystore | 证书库的名称 |
-storepass | 证书库的密码 |
-keypass | 证书的密码 |
-list | 显示密钥库中的证书信息 |
-v | 显示密钥库中的证书详细信息 |
-export | 显示密钥库中的证书信息 |
-file | 指定导出证书的文件名和路径 |
-delete | 删除密钥库中某条目 |
-import | 将已签名数字证书导入密钥库 |
-keypasswd | 修改密钥库中指定条目口令 |
-dname | 指定证书拥有者信息 |
-keyalg | 指定密钥的算法 |
-validity | 指定建立的证书有效期多少天 |
-keysize | 指定密钥长度 |
keytool -genkey -alias nettyServer -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=localhost" -keypass 证书密码 -storepass 服务端的证书仓库密码 -keystore serverCerts.jks
keytool -export -alias nettyServer -keystore serverCerts.jks -storepass 服务端的证书仓库密码 -file serverCert.cer
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
keytool -export -alias nettyClient -keystore clientCerts.jks -file nettyclientCert.cer -storepass 客户端的证书仓库密码
keytool -import -trustcacerts -alias smcc -file nettyClientCert.cer -storepass 服务端的证书仓库密码 -keystore serverCerts.jks
keytool -import -trustcacerts -alias smccClient -file serverCert.cer -storepass 客户端的证书仓库密码 -keystore clientCerts.jks
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 ; } }
这里须要注意的是 SslHandler须要添加到pipeline的最前面,不然即便加上了,不合法的客户端同样能够正常链接spring
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(); }
客户端代码基本是相似的,这里就不贴了。服务器