前言:
最近完成一個項目,安全級別比較高。所以涉及到https雙向認證,在網上找了很多資料都沒有完美的解決方案。最後參考了org.sandrob.sslexample的實現方式,結合實際情況才完成該技術難題,現在分享一下我的實現方案來彌補這方面的空白。
正文:
1.android 4.0(不包含)以下版本的實現方法:
1.1 書寫認證
private SSLContext createSSLContext() {
SSLContext localSSLContext = null;
try {
// 創建一個證書庫,並將證書導入證書庫
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
keyStore.load(
mContext.getResources().openRawResource(R.raw.client),//client 是*.pfx文件
CERTFILE_PASSWORD.toCharArray());//CERTFILE_PASSWORD 爲你的證書的密碼
KeyManagerFactory localKeyManagerFactory = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
localKeyManagerFactory.init(keyStore,
CERTFILE_PASSWORD.toCharArray());
KeyManager[] arrayOfKeyManager = localKeyManagerFactory
.getKeyManagers();
localSSLContext = SSLContext.getInstance("TLS");
localSSLContext.init(arrayOfKeyManager, trustAllCerts,
new SecureRandom());
} catch (Exception ex) {
ex.printStackTrace();
}
return localSSLContext;
}
/**
* 設置webview的ssl雙向認證
* 注意:改方法只支持android4.0(不包含)一下
* 該方法調用一次即可
* <P>Author : mingli </P>
* <P>Date : 2013-7-2 </P>
*/
public boolean setWebViewSSLCert() {
boolean issuc = false;// true 代表驗證和設置成功
if (Build.VERSION.SDK_INT >= 14){
return issuc;
}
try {
Field[] arrayOfField = Class.forName(
"android.net.http.HttpsConnection").getDeclaredFields();
for (Field localField : arrayOfField) {
if (localField.getName().equals("mSslSocketFactory")) {//採用反射的方式修改mSslSocketFactory變量
localField.setAccessible(true);
localField.set(null,createSSLContext().getSocketFactory());
issuc = true;
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return issuc;
}
1.2 調用 在webview初始化或者application 等,需要用https認證的地方調用 setWebViewSSLCert方法即可。
2.android 4.0(包含)以上版本的實現方法:
2.1 書寫認證
private X509Certificate[] mX509Certificates;
private PrivateKey mPrivateKey;
private void initPrivateKeyAndX509Certificate()
throws Exception {
KeyStore keyStore;
// 創建一個證書庫,並將證書導入證書庫
KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
keyStore.load(
mContext.getResources().openRawResource(R.raw.client),
CERTFILE_PASSWORD.toCharArray());
Enumeration<?> localEnumeration;
localEnumeration = keyStore.aliases();
while (localEnumeration.hasMoreElements()) {
String str3 = (String) localEnumeration.nextElement();
mPrivateKey = (PrivateKey) keyStore.getKey(str3,
CERTFILE_PASSWORD.toCharArray());
if (mPrivateKey == null) {
continue;
} else {
Certificate[] arrayOfCertificate = keyStore
.getCertificateChain(str3);
mX509Certificates = new X509Certificate[arrayOfCertificate.length];
for (int j = 0; j < mX509Certificates.length; j++) {
mX509Certificates[j] = ((X509Certificate) arrayOfCertificate[j]);
}
}
}
}
public class BasicWebViewClientEx extends WebViewClient {
private X509Certificate[] certificatesChain;
private PrivateKey clientCertPrivateKey;
public BasicWebViewClientEx(AbstractActivity activity) {
mActivity = activity;
certificatesChain = getX509Certificates();//此處就是上文中的mX509Certificates
clientCertPrivateKey = getPrivateKey();//次處就是上文中的mPrivateKey
}
public void onReceivedClientCertRequest(WebView view,
ClientCertRequestHandler handler, String host_and_port) {
//注意該方法是調用的隱藏函數接口。這兒是整個驗證的技術難點:就是如何調用隱藏類的接口。
//方法:去下載一個android4.2版本全編譯後的class.jar 然後導入到工程中
if((null != clientCertPrivateKey) && ((null!=certificatesChain) && (certificatesChain.length !=0))){
handler.proceed(this.clientCertPrivateKey, this.certificatesChain);
}else{
handler.cancel();
}
}
@Override
public void onReceivedSslError(final WebView view, SslErrorHandler handler,
SslError error) {
handler.proceed();
}
}
2.2 調用
mWebView.setWebViewClient(new BasicWebViewClientEx());
2.3 編譯
方案二:(推薦)
1.去下載一個全編譯的class.jar(http://download.csdn.net/detail/sfhong2008/5506219)
2.把該class.jar導入工程。步驟如下:(http://www.linuxidc.com/Linux/2012-02/54978.htm)
使用Eclipse,Android工程添加library(BuildPath -> Add Libraries->User Library->New User Library),將.jar文件加入添加到library,同時勾選“SystemLibrary”選項,www.linuxidc.com 以避免產生“java.lang.OutOfMemoryError:Java Heap Space”錯誤。如果已經正確導入了jar庫,卻仍然找不到隱藏的API。原因可能是Buildclass path order不正確,即android.jar和classes.jar的導入順序不對,具體調節Buildclass path order,選擇Build Path-> Config Build Path->Order and Export,調整自定義的library與android.jar的順序。
3.編譯
後記:
分享完畢,歡迎大家拍磚和提問哦。共同進步……