以前一篇中說了如何 創建 https 通訊的完整流程,其中涉及了java web容器 tomcat,關於它的配置是: java
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="true" sslProtocol="TLS" keystoreFile="D:\ssl\server.keystore" keystorePass="123456" truststoreFile="D:\ssl\server.keystore" truststorePass="123456"/>
對應的keyStore(包括私鑰庫和受信任證書庫)是在tomcat啓動時一次性加載到內存中的。 web
大多數的場景這就夠了,可是若是 要構建一個 基於https、受信任證書的 權限驗證體系,像上邊的那樣 一次性加載 keyStore 就算 咱們從鍵庫中刪除某個證書,程序是沒辦法探知的。我急需一種熱加載 keyStore的技術。 apache
咱們修改對應的配置爲 瀏覽器
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="true" sslProtocol="TLS" keystoreFile="d:/ssl/server.keystore" keystorePass="123456" trustManagerClassName="MyTrustManager"/>
這裏 本身的私鑰鍵庫是不須要也是不能從新加載的,關鍵在與證書鍵庫,咱們建立了一個在自定義的類叫 tomcat
MyTrustManager 用來管理受信任證書,他須要實現接口 X509TrustManager 並提供一個無參的構造函數。 ide
而後將其打包成jar後,部署到tomcat的lib目錄(注意connector是在tomcat啓動時構建的,因此代碼不能放在你本身的web項目裏,由於當時tomcat尚未classLoad你的類呢)下邊是參考代碼 函數
public class MyTrustManager implements X509TrustManager { public MyTrustManager(){} @Override public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { System.out.println("check"); if(x509Certificates==null||x509Certificates.length==0||s==null||s.length()==0) throw new IllegalArgumentException(); KeyStore store=getKeyStore(); boolean pass=false; try { for(X509Certificate certificate:x509Certificates){ certificate.checkValidity(); String theAlias = store.getCertificateAlias(certificate); if(theAlias!=null)pass=true; } } catch (KeyStoreException e) { e.printStackTrace(); } System.out.println("pass "+pass); if(!pass)throw new CertificateException(); } @Override public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { if(x509Certificates==null||x509Certificates.length==0||s==null||s.length()==0) throw new IllegalArgumentException(); for(X509Certificate certificate:x509Certificates){ certificate.checkValidity(); } } @Override public X509Certificate[] getAcceptedIssuers() { ArrayList<X509Certificate> trusts=new ArrayList<X509Certificate>(); try { KeyStore store=getKeyStore(); Enumeration<String> alias = store.aliases(); while (alias.hasMoreElements()){ String name = alias.nextElement(); if(store.isCertificateEntry(name)){ X509Certificate trust = (X509Certificate) store.getCertificate(name); trusts.add(trust); } } } catch (Exception e) { e.printStackTrace(); } X509Certificate[] trustsArr = trusts.toArray(new X509Certificate[0]); System.out.println("return trust array "+trustsArr.length); return trustsArr; } private KeyStore getKeyStore() throws CertificateException { try { KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); store.load(new FileInputStream("D:/ssl/server.keystore"),"123456".toCharArray()); return store; } catch (Exception e) { e.printStackTrace(); throw new CertificateException(); } } }
checkClientTrusted 是對client提交過來的證書進行驗證,certificate.checkValidity();驗證證書是否過時,store.getCertificateAlias(certificate)從本身的鍵庫中尋找對應的證書,不存在返回null,發現驗證不經過 就本身手動拋出一個異常CertificateException,這樣容器就知道如何處理了。 性能
getKeyStore中是加載鍵庫,因爲每次驗證時才加載鍵庫,因此就實現了熱加載。固然爲了性能你能夠把keyStore放到某個全局變量裏,在須要的時候對其進行reload。 spa
綜上所述,你能夠實現一個經過添加信任證書的方式來對請求方進行控制的系統了。 .net
注意:https爲了性能在創建了SSL-SESSION以後容許再也不進行證書驗證,你在瀏覽器裏訪問作實驗須要關閉瀏覽器後從新訪問纔會看到keyStore更新生效,你也能夠經過代碼設法銷燬SSL-SESSION讓每次https請求都從新握手驗證。參考:http://blog.csdn.net/ibznphone/article/details/7846879