Volley支持https请求

老版本的Volley是不支持https的,新版本的Volley是可以支持https的,不过呢,如果服务器是自签名SSL,并且app端需要检验证书,Volley就不行了,需要借助okhttp。本文将对服务器自签名的情况下,app端检验分三种情况:第一,app不检验证书(Volley+okhttp);第二,app端不检验证书(新版Volley);第三,app需要检验证书(Volley+okhttp)。

先来看一下Volley创建请求队列的方法:

RequestQueue newRequestQueue (Context context)  和 RequestQueue newRequestQueue (Context context, HttpStack stack) 

第一个方法不多说了,创建的队列用的是默认的HttpStack。要让Volley借助ok支持https,我们需要自定HttpStack,如下代码:

import android.util.Log;

import com.android.volley.toolbox.HurlStack;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.OkUrlFactory;

import java.io.IOException;
import java.io.InputStream;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

/**
 * Created by cyq on 2016/6/17.
 */
public class SelfHttpsStack extends HurlStack {

    private static String TAG = "SelfHttpsStack";
    private OkHttpClient okHttpClient;

    public SelfHttpsStack(InputStream is) {
        buildOkHttpClient(is);
    }

    @Override
    protected HttpURLConnection createConnection(URL url) throws IOException {
        if ("https".equals(url.getProtocol()) ) {
            HttpsURLConnection connection = (HttpsURLConnection) new OkUrlFactory(okHttpClient).open(url);
            connection.setSSLSocketFactory(okHttpClient.getSslSocketFactory());
            return connection;
        } else {
            return  new OkUrlFactory(okHttpClient).open(url);
        }
    }
    private void buildOkHttpClient(InputStream cerInputStream) {
        if (okHttpClient == null) {
            okHttpClient = new OkHttpClient();
            okHttpClient.setHostnameVerifier(new TrustAllHostnameVerifier());
            okHttpClient.setSslSocketFactory(createSSLSocketFactory());
            if (cerInputStream != null) {
                //okHttpClient.setSslSocketFactory(createSSLSocketFactory(cerInputStream));
            }
            //CookieManager 是 CookieHandler 的子类
            okHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
        }
    }
    // 创建不检验证书的SSLSokectFactory
    private static SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory sSLSocketFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllManager()}, new SecureRandom());
            sSLSocketFactory = sc.getSocketFactory();
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
        }
        return sSLSocketFactory;
    }
    // 创建需要检验证书的SSLSokectFactory
    private static SSLSocketFactory createSSLSocketFactory(InputStream cerInputStream) {
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            keyStore.setCertificateEntry("qxueyou", certificateFactory.generateCertificate(cerInputStream));
            cerInputStream.close();

            SSLContext sslContext = SSLContext.getInstance("TLS");

            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

            trustManagerFactory.init(keyStore);
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
        }
        return null;
    }

    private static class TrustAllManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    // 自定义域名检验类
    private static class TrustAllHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
}
使用示例: RequestQueue queue = Volley.newRequestQueue(context, new SelfHttpsStack(null));

quene.start();

StringRequest stringRequest = new StringRequest(...)

queue.add(stringRequest);

以上即是第一种情况:app不检验证书。

如果app需要校验证书怎么办呢?很简单,上面的类已经支持了,只要把buildOkHttpClient方法的okHttpClient.setSslSocketFactory(createSSLSocketFactory());改为okHttpClient.setSslSocketFactory(createSSLSocketFactory(cerInputStream));(代码中已注释)

使用时只要将证书传入即可,如RequestQueue queue = Volley.newRequestQueue(context, new SelfHttpsStack(context.getAssets().open("tomcat.cer")));

以上便是第二种情况:app需要校验证书。

最后再来看看使用新版的Volley不校验证书支持https(需要支持校验证书同上)

原理,创建X509TrustManager的子类,忽略域名校验,完整代码如下:

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class FakeTrustManager implements X509TrustManager {

    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 | File Templates.
    }

    @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 | File Templates.
    }

    public boolean isClientTrusted(X509Certificate[] chain) {
        return true;
    }

    public boolean isServerTrusted(X509Certificate[] chain) {
        return true;
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return _AcceptedIssuers;
    }

    public static void allowAllSSL() {
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

            @Override
            public boolean verify(String arg0, SSLSession arg1) {
                // TODO Auto-generated method stub
                return true;
            }

        });

        SSLContext context = null;
        if (trustManagers == null) {
            trustManagers = new TrustManager[] { new FakeTrustManager() };
        }

        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());
    }

}
在发送请求前调用即可,如:



FakeTrustManager.allowAllSSL();

RequestQueue queue = Volley.newRequestQueue(context);

quene.start();

StringRequest stringRequest = new StringRequest(...)

queue.add(stringRequest);


水平有限,欢迎指正~





FakeTrustManager.allowAllSSL();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunfount

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值