您的位置:首页 > 理论基础 > 计算机网络

android 让webview支持https 双向认证(SSL)

2016-07-08 13:06 627 查看


前言:

参考了org.sandrob.sslexample和http://blog.csdn.net/mingli198611/article/details/9233705的实现方式,结合实际情况才完成该技术难题,现在分享一下我的实现方案来弥补这方面的空白。


正文:


1.android 4.0(不包含)以下版本的实现方法:


1.1 书写认证

[java] view
plain copy

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;  

    }  

[java] view
plain copy

/** 

     * 设置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 书写认证

[java] view
plain copy

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 编译

方案一:到android 4.2 源码环境下编译

方案二:(推荐)

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.编译
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: