Android Volley的使用(三)Volley中如何使用https

来源:互联网 发布:洛阳达内大数据培训 编辑:程序博客网 时间:2024/06/04 19:56

概念

https(Hyper Text TransferProtocol over Secure Socket Layer)简单讲就是在http中加入了SSL(Secure Sockets Layer,安全套接层)层的安全版本。https请求是安全的,所以请求过程中不可以被抓包。

在典型的 SSL 使用场景中,会使用一个包含公钥及与其匹配的私钥的证书配置服务器。让客户端也拥有其信任的一个或多个证书集。如果请求的URL地址时发现证书不在此集合中,则不会信任服务器而请求失败。但是这样做也存在缺点。服务器在后续时间里可能存在升级更强的密钥,使用新的公钥替换证书中的公钥。这时由于客户端不能及时更新的话就会出现问题。

为弥补这些缺点,通常使用来自知名颁发者(称为证书颁发机构 (CA))发放的证书配置服务器。主机平台一般包含其信任的知名 CA 的列表。从 Android 4.2 (Jelly Bean) 开始,Android 目前包含在每个版本中更新的100 多个 CA。CA 具有一个证书和一个私钥,这点与服务器相似。为服务器发放证书时,CA 使用其私钥签署服务器证书。然后,客户端可以验证该服务器是否具有平台已知的 CA 发放的证书。详细可以参考官方说明https://developer.android.com/training/articles/security-ssl.html。

实现1

根据上面概念介绍,如果服务器是使用来自知名证书颁发机构发放的证书配置,那么在Android里会自动帮忙我们去验证该证书是否有效,我们在使用Volley请求网络时,根本就是不需要做任何事情,只需要将http URL改成https URL即可。

实现2

如果服务器没有使用第三方知名证书颁发机构发放的证书配置,是通过典型使用场景,即使用一个包含公钥及与其匹配的私钥的证书配置服务器。那么也需要客户端配置与其匹配的证书。我们在《Android Volley的使用(一)基本网络请求》中介绍到可以通过代码

RequestQueue requestQueue =Volley.newRequestQueue(getApplicationContext()); 

来创建请求队列RequestQueue对象。其实我们从源码中可以发现,newRequestQueue方法还有一个重载的版本:newRequestQueue(Context context, HttpStack stack)。那么客户端配置证书使用如下:

SSLSocketFactory sslSocketFactory =initSSLSocketFactory();HurlStack stack = new HurlStack(null,sslSocketFactory);RequestQueue requestQueue =Volley.newRequestQueue(mContext, stack);
private final String RFC ="XXX..."; /** * 生成SSLSocketFactory * 这里的代码与之前相比,没有什么不同 * *@return */private SSLSocketFactoryinitSSLSocketFactory() {   //生成证书:Certificate   CertificateFactory cf = null;   SSLSocketFactory factory = null;   try {       cf = CertificateFactory.getInstance("X.509");       InputStream caInput = new ByteArrayInputStream(RFC.getBytes());                     // 通过证书生成的RFC格式数据字符串       //InputStream caInput = new BufferedInputStream(newFileInputStream("xxx.crt"));       // 证书文件        Certificate ca = null;       try {           ca = cf.generateCertificate(caInput);       } finally {           try {                caInput.close();           } catch (IOException e) {                e.printStackTrace();           }       }        //初始化公钥:keyStore       String keyType = KeyStore.getDefaultType();       KeyStore keyStore = KeyStore.getInstance(keyType);       keyStore.load(null, null);       keyStore.setCertificateEntry("ca", ca);        //初始化TrustManagerFactory       String algorithm = TrustManagerFactory.getDefaultAlgorithm();       TrustManagerFactory managerFactory =TrustManagerFactory.getInstance(algorithm);       managerFactory.init(keyStore);        //初始化sslContext       SSLContext sslContext = SSLContext.getInstance("TLS");       sslContext.init(null, managerFactory.getTrustManagers(), null);       factory = sslContext.getSocketFactory();     }catch (CertificateException e) {       e.printStackTrace();    }catch (NoSuchAlgorithmException e) {       e.printStackTrace();    }catch (KeyStoreException e) {       e.printStackTrace();    }catch (IOException e) {       e.printStackTrace();    }catch (KeyManagementException e) {       e.printStackTrace();    }    return factory;}

实现3

这种方法属性比较极端的做法,就是跳转证书验证。其实使用https请求验证是否合法,在Volley中主要是HostnameVerifier接口中的verify方法进行验证,所以如果我们在此方法中返回true,则可以跳过证书的验证,实现如下:

新建SsX509TrustManager类,并继承X509TrustManager

public class SsX509TrustManager implementsX509TrustManager {   private static TrustManager[] trustManagers;   private static final X509Certificate[] _AcceptedIssuers = new           X509Certificate[]{};    @Override   public void checkClientTrusted(java.security.cert.X509Certificate[]x509Certificates, String s) throws java.security.cert.CertificateException {       //To change body of implemented methods use File | Settings | FileTemplates.    }    @Override   public void checkServerTrusted(java.security.cert.X509Certificate[]x509Certificates, String s) throws java.security.cert.CertificateException {       //To change body of implemented methods use File | Settings | FileTemplates.    }    public boolean isClientTrusted(X509Certificate[] chain) {       return true;    }    public boolean isServerTrusted(X509Certificate[] chain) {       return true;    }    @Override   public X509Certificate[] getAcceptedIssuers() {       return _AcceptedIssuers;    }    /**    * 允许所有的SSL请求,添加在new StringRequest()之前    */   public static void allowAllSSL() {       HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {            @Override           public boolean verify(String arg0, SSLSession arg1) {                return true;           }        });        SSLContext context = null;       if (trustManagers == null) {           trustManagers = new TrustManager[]{new SsX509TrustManager()};       }        try {           context = SSLContext.getInstance("TLS");           context.init(null, trustManagers, new SecureRandom());       } catch (NoSuchAlgorithmException e) {           e.printStackTrace();       } catch (KeyManagementException e) {           e.printStackTrace();       }        HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());    }}

然后在创建请求Request对象前加上一行代码:SsX509TrustManager.allowAllSSL();即可,如:

RequestQueue requestQueue =Volley.newRequestQueue(getApplicationContext()); SsX509TrustManager.allowAllSSL();StringRequest stringRequest = newStringRequest(Request.Method.GET, "https://kyfw.12306.cn/otn/regist/init",        new Response.Listener<String>() {            @Override            public void onResponse(String s) {                 // 请求成功            }        },        new Response.ErrorListener() {             @Override            public void onErrorResponse(VolleyError volleyError) {                 // 请求失败            }        }); requestQueue.add(stringRequest);