FileDownLoader https 无法下载问题(SSLHandshakeException)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011520181/article/details/82227377

1、问题:

项目下载改为 https 协议,连接代理后使用 liulishuo 的 FileDownLoader 无法下载,抛出异常如下:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

2、原因:

没有信任证书或该域名的根证书不被信任

3、解决方案:

方案一:添加证书文件,参考这篇博客

方案二:在程序中绕过证书校验;

本文采用的是方案二,绕过证书校验。具体步骤如下:

  1. 自定制 OkHttp3Connection 替换 FileDownload 的默认连接方式(FileDownloadUrlConnection)

  2. 在创建 OkHttpClient.Builder 的时候复写 hostnameVerifier ,并创建TrustManager 忽略 SSL 验证

  3. 使用FileDownloader.setupOnApplicationOnCreate(this).connectionCreator(....)的方式注册 FileDownloader

FileDownLoader 初始化代码:

public class FileDownloaderHelper {

    // 超时设置 单位 秒
    private static final int READ_TIMEOUT = 5 * 60;
    private static final int WRITE_TIMEOUT = 5 * 60;
    private static final int CONNECT_TIMEOUT = 30;

    /**
    * 在主进程的 Application 的 onCreate 里调用
    */
    public static void setup(Application application) {
        FileDownloader.setup(application);
    }

    /**
    * 在 FileDownLoader 进程的 Application 的 onCreate 里调用,绕过 SSL 认证代码如果不在 FileDownLoader 进程调用也无效
    */
    public static void initInDownloadProcess(Application application) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
                .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
		// 添加 SSL 认证
        SSLTrustManager.addVerify(builder);

        FileDownloader.setupOnApplicationOnCreate(application)
                .connectionCreator(new OkHttp3Connection.Creator(builder))// 自实现 OkHttp3Connection
                .commit();
    }
}

 看下如何绕过 SSL 认证,代码如下:

public class SSLTrustManager {

    public static void addVerify(OkHttpClient.Builder builder) {
        if (builder == null) {
            return;
        }
        builder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                // 这里是所有域名都绕过 SSL 验证,最好是只添加信任的域名
                return true;
            }
        });
        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, new TrustManager[]{xtm}, new SecureRandom());
            builder.sslSocketFactory(sslContext.getSocketFactory(), xtm);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    private static X509TrustManager xtm = new X509TrustManager() {
        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

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

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

OkHttp3Connection 实现如下:

public class OkHttp3Connection implements FileDownloadConnection {

    private OkHttpClient mClient;
    private Request.Builder mRequestBuilder;

    private Request mRequest;
    private Response mResponse;

    public OkHttp3Connection(String url, OkHttpClient client) {
        try {
            mRequestBuilder = new Request.Builder().url(url);
            mClient = client;
        } catch (Exception e) {
            LogUtil.e(e.getMessage());
        }
    }

    @Override
    public void addHeader(String name, String value) {
        mRequestBuilder.addHeader(name, value);
    }

    @Override
    public boolean dispatchAddResumeOffset(String etag, long offset) {
        return false;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        if (mResponse == null) throw new IllegalStateException("Please invoke #execute first!");
        return mResponse.body().byteStream();
    }

    @Override
    public Map<String, List<String>> getRequestHeaderFields() {
        if (mRequest == null) {
            mRequest = mRequestBuilder.build();
        }

        return mRequest.headers().toMultimap();
    }

    @Override
    public Map<String, List<String>> getResponseHeaderFields() {
        return mResponse == null ? null : mResponse.headers().toMultimap();
    }

    @Override
    public String getResponseHeaderField(String name) {
        return mResponse == null ? null : mResponse.header(name);
    }

    @Override
    public boolean setRequestMethod(String method) throws ProtocolException {
        return true;
    }

    @Override
    public void execute() throws IOException {
        if (mRequest == null) {
            mRequest = mRequestBuilder.build();
        }

        mResponse = mClient.newCall(mRequest).execute();
    }

    @Override
    public int getResponseCode() throws IOException {
        if (mResponse == null) throw new IllegalStateException("Please invoke #execute first!");

        return mResponse.code();
    }

    @Override
    public void ending() {
        mRequest = null;
        mResponse = null;
    }

    /**
     * The creator for the connection implemented with the okhttp3.
     */
    public static class Creator implements FileDownloadHelper.ConnectionCreator {

        private OkHttpClient mClient;
        private OkHttpClient.Builder mBuilder;

        public Creator() {
        }

        /**
         * Create the Creator with the customized {@code client}.
         *
         * @param builder the builder for customizing the okHttp client.
         */
        public Creator(OkHttpClient.Builder builder) {
            mBuilder = builder;
        }

        @Override
        public OkHttp3Connection create(String url) throws IOException {
            if (mClient == null) {
                synchronized (Creator.class) {
                    if (mClient == null) {
                        mClient = mBuilder != null ? mBuilder.build() : new OkHttpClient();
                        mBuilder = null;
                    }
                }
            }
            return new OkHttp3Connection(url, mClient);
        }
    }
}

大功告成!

参考链接:

https://stackoverflow.com/questions/2642777/trusting-all-certificates-using-httpclient-over-https/6378872#6378872

https://github.com/lingochamp/FileDownloader/issues/437

猜你喜欢

转载自blog.csdn.net/u011520181/article/details/82227377
今日推荐