Android低版本(4.4)okhttp 网络适配

这篇具有很好参考价值的文章主要介绍了Android低版本(4.4)okhttp 网络适配。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

访问网络时,出现错误:

javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb7eabc88: Failure in SSL library, usually a protocol error    error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:741 0xa4fb8d5c:0x00000000)

SSLSocket的setEnabledProtocols配置支持TLSv1.1,TLSv1.2协议

错误:java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

可以给客户端安装证书

除了给客户端安装证书外,还有其他的解决办法

1、忽略所有证书验证

2、自定义对证书验证(需要将证书提前放到assert文件夹中)


访问网络时,出现错误:

javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb7eabc88: Failure in SSL library, usually a protocol error     error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version (external/openssl/ssl/s23_clnt.c:741 0xa4fb8d5c:0x00000000)

通过Https通信,客户端与服务端在SSL/TLS层建立安全连接前,涉及到版本协商过程。

Android 4.4默认支持的SSL/TLS版本是SSLv3(1996发布,2015弃用),TLSv1(1996发布)。但TLSv1.1,TLSv1.2(主流)实际上也是在其支持范围内的,需要人为去配置。

SSLSocket的setEnabledProtocols配置支持TLSv1.1,TLSv1.2协议

在okhttp中,建立Tls连接,创建套接字是通过SSLSocketFactory实现的,重写SSLSocketFactory,通过SSLSocketsetEnabledProtocols(String protocols[]),使其支持TLSv1.1,TLSv1.2。最后将其设置给OkHttpClient

SSLSocketFactory factory = new SSLSocketFactoryCompat(context);

// okhttpClient的builder
builder.sslSocketFactory(factory);
public class SSLSocketFactoryCompat extends SSLSocketFactory{
    private static final String[] TLS_V12_ONLY = {"TLSv1.2"};

    private final SSLSocketFactory delegate;

    public SSLSocketFactoryCompat() throws KeyManagementException, NoSuchAlgorithmException {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, null, null);
        delegate = sc.getSocketFactory();
    }

    public SSLSocketFactoryCompat(SSLSocketFactory delegate) {
        if (delegate == null) {
            throw new NullPointerException();
        }
        this.delegate = delegate;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        return delegate.getSupportedCipherSuites();
    }

    private Socket enableTls12(Socket socket) {
        if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 20) {
            if (socket instanceof SSLSocket) {
                ((SSLSocket) socket).setEnabledProtocols(TLS_V12_ONLY);
            }
        }
        return socket;
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        return enableTls12(delegate.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException {
        return enableTls12(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
        return enableTls12(delegate.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        return enableTls12(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        return enableTls12(delegate.createSocket(address, port, localAddress, localPort));
    }
}

然而,通过上述配置后,有些url还是无法访问,会出现

错误:java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

这里我遇到的问题是客户端没有对应的根CA证书导致的

可以给客户端安装证书

在浏览器网站上,输入在Android上访问出错的url,点击链接-连接-证书有效-详细信息,证书链汇中选择最上面一个,导出根证书

安卓4.4 okhttp3 getsslsocketfactoryforoneway 配置tls1.1,okhttp,网络

导出后将文件传入Androidsd卡中,然后在设置中找到安装证书的选项。

或者,在代码中打开安装证书的设置

    /**
     * 安裝证书
     */
    public void installCert(Context context) {
        InputStream assetsIn = null;
        Intent intent = KeyChain.createInstallIntent();
        try {
            //获取证书流,注意参数为assets目录文件全名
            assetsIn = context.getAssets().open("a.cer");
            byte[] cert = new byte[10240];
            assetsIn.read(cert);
            javax.security.cert.X509Certificate x509 = null;
            try {
                x509 = javax.security.cert.X509Certificate.getInstance(cert);
                //将证书传给系统
                intent.putExtra(KeyChain.EXTRA_CERTIFICATE, x509.getEncoded());
            } catch (CertificateException e) {
                e.printStackTrace();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        //此处为给证书设置默认别名,第二个参数可自定义,设置后无需用户输入
        intent.putExtra("name", "gz");
        startActivity(intent);
    }

安卓4.4 okhttp3 getsslsocketfactoryforoneway 配置tls1.1,okhttp,网络  

安装成功后,尝试是否可以访问链接。

除了给客户端安装证书外,还有其他的解决办法

1、忽略所有证书验证

2、自定义对证书验证(需要将证书提前放到assert文件夹中)

改造一下SSLSocketFactory文章来源地址https://www.toymoban.com/news/detail-796575.html


import android.content.Context;
import android.os.Build;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;


public class SSLSocketFactoryCompat extends SSLSocketFactory{
    private static final String[] TLS_V12_ONLY = {"TLSv1.1"};
    private static final String TAG = "TAG";

    private final SSLSocketFactory delegate;
    private X509TrustManager trustManager;
    private Context context;

    public SSLSocketFactoryCompat(Context context) throws KeyManagementException, NoSuchAlgorithmException {
        this.context = context;
        /*
            a.cer是浏览器导出的CA根证书(这里没有用到,另外一个解决方法 安装到设备中的)
            j.pem证书中存储了服务器的公钥等信息,并没有经过CA机构的加密,一般是由服务器导出
         */

//        delegate = getSslSocketFactoryTrustALL();
        delegate = getSslSocketFactorySpecificVerify();
    }

    // 默认创建代理方式
    private SSLSocketFactory getSslSocketFactoryDefault() throws NoSuchAlgorithmException, KeyManagementException {
        final SSLSocketFactory delegate;
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, null, null);
        delegate = sc.getSocketFactory();
        return delegate;
    }

    // 自定义证书校验
    private SSLSocketFactory getSslSocketFactorySpecificVerify() throws KeyManagementException, NoSuchAlgorithmException {
        final SSLSocketFactory delegate;
        SSLContext sc = SSLContext.getInstance("TLS");

        // 自定义证书验证
        trustManager = new X509TrustManager() {

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

            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                if (chain == null || chain.length == 0) {
                    throw new CertificateException("checkServerTrusted: X509Certificate array is null");
                }

                if (!(null != authType && authType.equals("ECDHE_RSA"))) {
                    throw new CertificateException("checkServerTrusted: AuthType is not ECDHE_RSA");
                }
                //判断证书是否是本地信任列表里颁发的证书(系统默认的验证)
                try {
                    TrustManagerFactory factory = TrustManagerFactory.getInstance("X509");
                    factory.init((KeyStore) null);
                    for (TrustManager trustManager : factory.getTrustManagers()) {
                        ((X509TrustManager) trustManager).checkServerTrusted(chain, authType);
                    }
                    Log.i("TAG", "checkServerTrusted: 本地");
                    return;//用系统的证书验证服务器证书,验证通过就不需要继续验证证书信息;也可以注释掉,继续走自己的服务器证书逻辑
                } catch (Exception e) {
                    Log.i(TAG, "checkServerTrusted: " + e.getMessage());
                    e.printStackTrace();
                    //注意这个地方不能抛异常,用系统的证书验证服务器证书,没通过就用自己的验证规则
//                        throw new CertificateException(e);
                }

                //获取本地证书中的信息
                String clientEncoded = "";//公钥
                String clientSubject = "";//颁发给
                String clientIssUser = "";//颁发机构
                try (InputStream inputStream = getAssetFileInputStream(context, "j.pem")) {
                    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                    X509Certificate clientCertificate = (X509Certificate) certificateFactory.generateCertificate(inputStream);
                    clientEncoded = new BigInteger(1, clientCertificate.getPublicKey().getEncoded()).toString(16);
                    clientSubject = clientCertificate.getSubjectDN().getName();
                    clientIssUser = clientCertificate.getIssuerDN().getName();
                    Log.i("TAG", "clientEncoded: " + clientEncoded);
                    Log.i("TAG", "clientSubject: " + clientSubject);
                    Log.i("TAG", "clientIssUser: " + clientIssUser);

                } catch (Exception e) {
                    e.printStackTrace();
                    throw new CertificateException(e);
                }

                //获取网络中的证书信息
                X509Certificate certificate = chain[0];
                PublicKey publicKey = certificate.getPublicKey();
                String serverEncoded = new BigInteger(1, publicKey.getEncoded()).toString(16);

                if (!clientEncoded.equals(serverEncoded)) {
                    Log.i("TAG", "checkServerTrusted: server's PublicKey is not equals to client's PublicKey");
                    throw new CertificateException("server's PublicKey is not equals to client's PublicKey");
                }
                String subject = certificate.getSubjectDN().getName();
                if (!clientSubject.equals(subject)) {
                    Log.i("TAG", "checkServerTrusted: server's SubjectDN is not equals to client's SubjectDN");
                    throw new CertificateException("server's SubjectDN is not equals to client's SubjectDN");
                }
                String issuser = certificate.getIssuerDN().getName();
                if (!clientIssUser.equals(issuser)) {
                    Log.i("TAG", "checkServerTrusted: server's IssuerDN is not equals to client's IssuerDN");
                    throw new CertificateException("server's IssuerDN is not equals to client's IssuerDN");
                }
            }

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

        sc.init(null, new TrustManager[]{trustManager}, new SecureRandom());
        delegate = sc.getSocketFactory();

        return delegate;
    }



    // 信任所有证书
    private SSLSocketFactory getSslSocketFactoryTrustALL() throws NoSuchAlgorithmException, KeyManagementException {
        final SSLSocketFactory delegate;
        trustManager = new 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() {
                Log.i("TAG", "getAcceptedIssuers: ");
                return new X509Certificate[0];
            }
        };
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
        delegate = sslContext.getSocketFactory();

        return delegate;
    }

    public SSLSocketFactoryCompat(SSLSocketFactory delegate) {
        if (delegate == null) {
            throw new NullPointerException();
        }
        this.delegate = delegate;
    }

    @Override
    public String[] getDefaultCipherSuites() {
        Log.i(TAG, "getDefaultCipherSuites: ");
        return delegate.getDefaultCipherSuites();
    }

    @Override
    public String[] getSupportedCipherSuites() {
        Log.i(TAG, "getSupportedCipherSuites: ");
        return delegate.getSupportedCipherSuites();
    }

    private Socket enableTls12(Socket socket) {
        Log.i(TAG, "enableTls12: ");
        if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 20) {
            if (socket instanceof SSLSocket) {
                ((SSLSocket) socket).setEnabledProtocols(TLS_V12_ONLY);
            }
        }
        return socket;
    }

    @Override
    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
        Log.i(TAG, "createSocket: ");
        return enableTls12(delegate.createSocket(s, host, port, autoClose));
    }

    @Override
    public Socket createSocket(String host, int port) throws IOException {
        Log.i(TAG, "createSocket: ");
        return enableTls12(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
        Log.i(TAG, "createSocket: ");
        return enableTls12(delegate.createSocket(host, port, localHost, localPort));
    }

    @Override
    public Socket createSocket(InetAddress host, int port) throws IOException {
        Log.i(TAG, "createSocket: ");
        return enableTls12(delegate.createSocket(host, port));
    }

    @Override
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
        Log.i(TAG, "createSocket: ");
        return enableTls12(delegate.createSocket(address, port, localAddress, localPort));
    }
    private static InputStream getAssetFileInputStream(Context context, String assetsFileName) {
        try {
            return context.getAssets().open(assetsFileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

到了这里,关于Android低版本(4.4)okhttp 网络适配的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android Okhttp3添加https自签名证书以及Glide4,Android高级工程师进阶学习—Android热修复原理

    二、自签名证书 什么是自签名证书(self-signed certicates)? 自签名证书就是没有通过受信任的证书颁发机构, 自己给自己颁发的证书. SSL 证书大致分三类: 由安卓认可的证书颁发机构CA(Certificate Authority)(如: VeriSign、DigiCert), 或这些机构的下属机构颁发的证书. 没有得到安卓认可的

    2024年04月17日
    浏览(29)
  • SpringBoot 整合okHttp3 okhttp3用法 okhttp整合 okhttp用法 SpringBoot 整合okHttp3

    GET 请求需要传递 application/json 参数 上述代码中,通过创建ConnectionPool对象,并将其设置到OkHttpClient中,从而启用了连接池功能。ConnectionPool的构造函数接受三个参数:maxIdleConnections、keepAliveDuration和timeUnit,用于配置连接池的最大空闲连接数、连接保持时间以及时间单位。 连

    2024年02月15日
    浏览(37)
  • Android 操作系统日历完成提醒功能 附带开关闹钟 适配高版本安卓

    如果想要一个稳定且不用担心生命周期的提醒方式,可以试试利用系统日历去完成任务的提醒或某个活动的预约。 项目仓库地址在文末 环境 Java 11 Android sdk 30 Gredle 7.1 测试机型 mi 8(安卓 9) mi10 pro(安卓11) huawei m8(安卓7) 日历操作表 ​ 其实完成这个功能本质是对安卓原

    2024年02月03日
    浏览(34)
  • Android实现App内自动升级,适配了安卓7、8及以上版本

            应用发布后,要实现灰度升级控制,如果只依赖各家应用市场是不够的,还需要自己在应用中控制升级逻辑。并且每家应用市场上新审核也是一件很麻烦的事情,尤其像至简网格这样的应用,甚至没在应用市场上架,更不可能依赖它们了。所以必须要在应用中实现自

    2024年02月10日
    浏览(49)
  • Android将Uri转为路径字符串(适配安卓全版本)并使用第三方应用打开文件(适配Android7.0+)

    做这个功能时在网上找了无数篇例子,有些方法是有问题的,故自己写一篇完整实现的总结,作备忘也作案例。顺便说一句,Android对存储权限的给予真的越来越严格 目录 1.Uri转为路径String以获得文件名  2.获取文件后缀名 3.通过后缀名获取文件MIME类型  4.设置Intent的Uri与权限

    2024年02月19日
    浏览(33)
  • web3j 引用报错:okhttp3.RequestBody okhttp3.RequestBody.create(java.lang.String, okhttp3.MediaType)解决

    在做区块链开发时引用了web3j,而web3j中又引用了OKhttp,在程序发起请求时报错如下 我项目中引用的web3j包如下 其实具体web3j哪个版本感觉都有类似问题,我尝试过4.6.3版本到5.0.0都会报上述错。然后看项目依赖发现引用的OKhttp版本是3.14.9,网上说要将OKhttp版本号更换到4.3.1以上

    2024年02月09日
    浏览(26)
  • Java之okhttp3请求方式

    在java开发中,发起http请求是非常常见的需求,常用的有HttpClient,下面聊一下okhttp3的请求方式。 1、引入okhttp3依赖 2、提供springboot工程及http接口 3、http请求 4、请求结果 get请求 post请求 form表单请求 可见发起http请求还是挺方便的,感兴趣的小伙伴可以试试~~~///( v )~~~

    2024年02月13日
    浏览(32)
  • com.squareup.okhttp3:okhttp 组件安全漏洞及健康度分析

    维护者 square组织 许可证类型 Apache License 2.0 首次发布 2016 年 1 月 2 日 最新发布时间 2023 年 4 月 23 日 GitHub Star 44403 GitHub Fork 9197 依赖包 5,582 依赖存储库 77,217 com.squareup.okhttp3:okhttp 一个开源的 HTTP 客户端库,可以用于 Android 和 Java 应用程序。它提供了一种简单而强大的方式来发

    2024年02月10日
    浏览(17)
  • SpringBoot集成websocket(4)|(使用okhttp3实现websocket)

    章节 第一章链接: SpringBoot集成websocket(1)|(websocket客户端实现) 第二章链接: SpringBoot集成websocket(2)|(websocket服务端实现以及websocket中转实现) HTTP是现代应用常用的一种交换数据和媒体的网络方式,高效地使用HTTP能让资源加载更快,节省带宽。OkHttp是一个高效的HTTP客户

    2024年02月10日
    浏览(31)
  • 安卓:网络框架okhttp

    目录 一、okhttp介绍 1. OkHttpClient类:  常用方法: 2. Request类:  常用方法: 3. Response类: 常用方法: 4. Call类: 常用方法:  5. Interceptor接口: 常用方法:  6. FormBody类: 常用方法: 7. MultipartBody类:  常用方法: 8. WebSocket类: 常用方法: 二、okhttp使用方法 1、添加依赖:

    2024年02月12日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包