OkHttp配置HTTPS訪問,核心爲如下三個部分:html
第一個是ssl套接字工廠,第二個用來驗證主機名,第三個是證書信任器管理類.經過OkHttp實現HTTPS訪問須要本身實現以上三部分.另外還簡單說起了服務器端的部署,用的是Tomcat9,最後是一些常見問題的可能解決方案.前端
OkHttp是一款開源的處理網絡請求的輕量級框架,有Square公司貢獻,用於替代HttpUrlConnection與Apache HttpClient,目前Github上有36.4k的star.優勢有java
總的來講OkHttp是一款支持get/post請求,支持文件上傳/下載的優秀的HTTP框架.git
什麼?都沒有?買! 固然證書能夠不用買,可使用openssl之類的工具生成,不過自簽名的證書後面驗證的時候會有點麻煩,建議仍是購買.github
public static String test() {
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(createSSLSocketFactory(), new TrustAllCerts())
.hostnameVerifier(new TrustAllHostnameVerifier()).build();
String url = "https://xxxxxxx"; //修改爲本身的url
Request request = new Request.Builder().url(url).build();
Call call = build.newCall(request);
Response response = call.execute();
if(response.body() != null)
{
String result = response.body().string();
//處理result
}
}
private static class TrustAllCerts implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}
}
private static class TrustAllHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) { return true; }
}
private static SSLSocketFactory createSSLSocketFactory() {
SSLSocketFactory ssfFactory = null;
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
ssfFactory = sc.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return ssfFactory;
}
複製代碼
這是一種暴力的方案,看類名就知道了,信任全部的證書與主機:web
public boolean verify(String hostname, SSLSession session) { return true; }
複製代碼
這個方法直接返回true,也就是信任全部的主機.後端
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
複製代碼
這裏兩個check函數沒有作任何的工做,表示接受任意的客戶端與服務端的證書.這樣寫的話至關因而使用了一個沒用的TrustManager,這樣還不如不加密,不推薦使用.數組
從兩方面入手修改,一是從X509TrustManager入手,二是從HostnameVerifier入手.緩存
先說個簡單的,這裏主要是驗證主機名,簡單的話,能夠以下實現:tomcat
HostnameVerifier hnv = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
if("www.test.com".equals(hostname)){
return true;
}
else {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify(hostname, session);
}
}
};
複製代碼
這裏驗證主機名是www.test.com就返回true,實現得比較簡單,業務複雜的話能夠結合配置中心,黑/白名單等動態校驗.
這裏其實有兩種方式,一種是以流的方式添加信任證書:
private static X509TrustManager trustManagerForCertificates(InputStream in) throws GeneralSecurityException {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
char[] password = "password".toCharArray(); // 這裏可使用任意密碼
KeyStore keyStore = newEmptyKeyStore(password);
int index = 0;
for (Certificate certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificate);
}
// Use it to build an X509 trust manager.
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager))
{
throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
}
return (X509TrustManager) trustManagers[0];
}
複製代碼
完整代碼見文末.這裏把工具類的方法實現成了靜態,調用時能夠直接:
OKHTTP.send("https://xxxxx");
複製代碼
另外一種方式是直接自定義一個TrustManager,重寫裏面的三個方法:
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] chain,String authType) throws CertificateException {
for (X509Certificate cert : chain) {
// Make sure that it hasn't expired.
cert.checkValidity();
// Verify the certificate's public key chain.
try {
cert.verify(((X509Certificate) ca).getPublicKey());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
}
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
}, null);
複製代碼
第一個方法爲
@Override
public void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException {}
複製代碼
該方法檢查客戶端的證書,因爲不須要對客戶端進行認證,默認便可. 第二個方法爲
@Override
public void checkServerTrusted(X509Certificate[] chain,String authType) 複製代碼
該方法檢查服務器的證書,若不信任該證書則拋出異常,經過本身實現該方法能夠信任任何本身指定的證書,不作任何處理的話,不會拋出任何異常,至關於信任全部證書.這裏檢查了證書是否過時以及證書的簽名是否匹配. 第三個方法爲
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
複製代碼
返回受信任的X509證書數組.
這種方法筆者沒有試過,僅供參考.
服務器用的是Tomcat,簡單介紹一下部署.
後端處理用的Spring Boot的工程,就不演示了,使用IDEA打成war包後上傳到webapps下便可.
重點說一下Tomcat的配置,首先須要一個域名,修改conf/server.xml文件,找到默認的名叫localhost的Host:
https://www.test.com:port
複製代碼
進行測試
這個由於沒有完整的Demo很難作驗證,具體來講前端用的OkHttp核心都介紹了,後端的話服務器Tomcat也介紹了,用Spring Boot作個Demo應該不難.
這裏只給出了工具類OKHTTP的源碼: github
1.蘋果核 - Android App 安全的HTTPS 通訊
2.Android OkHttp實現HTTPS訪問,支持Android 4.X系統HTTPS訪問
3.Android使用OkHttp請求自簽名的https網站
若是以爲文章好看,歡迎點贊. 同時歡迎關注微信公衆號:氷泠之路.