生成證書及代碼中有關密碼的操做,請按照大家本身的須要修改爲本身的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(); }
客戶端代碼基本是相似的,這裏就不貼了。服務器