zoukankan      html  css  js  c++  java
  • Android如何使用Https

    什么是Https?

      HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。它是一个URI Scheme(抽象标识符体系),句法类同Http:体系。用于安全的HTTP数据传输。Https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。这个系统的最初研发由网景公司(NetScape)进行,并内置于其浏览器Netscape Navigator中,提供了身份验证与加密通讯方法。现在它被广泛用于万维网上安全敏感的通讯,例如金融、网购等涉及支付的领域。    这次不装逼,我们来个深入浅出,先说最原始的Https,再说框架怎么框架怎么一句话使用Https

    Android用原始Java代码怎么用Https

      先普及一下Android怎么用最原始java代码请求网络,大神请掠过。   Android用Java开发,Java自带的http API有HttpURLConnection,Android系统又加上了Apache Httpclient,加上后来HttpClient在SDK中被Google删除,所以我们也不推荐使用HttpClient来做网络请求了,所以在这里呢也只给列出HttpURLConnection的方式。

    第一步:打开某个地址的连接

      这里咱打开我的博客地址,用GET方法请求

    URL url = new URL("http://blog.csdn.net/yanzhenjie1003");
    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
    urlConnection.setRequestMethod("GET");
    • 1
    • 2
    • 3
    • 1
    • 2
    • 3

    第二步:判断是Https请求,设置SSLSocketFactory

      如果是Https请求,那么做安全校验等操作,这里设置SSLSokcetFactory,这里有两种方法,一种是包涵Https证书的,一种是没有证书直接允许Https请求的,而证书不证书就是从SSLContext中来的:

    // 设置SSLSocketFoactory,这里有两种:1.需要安全证书 2.不需要安全证书;看官且往下看
    if (urlConnection instanceof HttpsURLConnection) { // 是Https请求
        SSLContext sslContext = SSLContextUtil.getSSLContext();
        if (sslContext != null) {
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslSocketFactory);
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

      那么SSLContext怎么生成呢,哈哈先不急,咱们先把这个请求的流程走完,证书的加载往后边看哦。

    第三步:设置必要属性

    // 设置属性
    urlConnection.setConnectTimeout(8 * 1000);
    urlConnection.setReadTimeout(8 * 1000);
    • 1
    • 2
    • 3
    • 1
    • 2
    • 3

    第四步:读取数据,发送到主线程,断开连接

    int responseCode = urlConnection.getResponseCode();
    if (responseCode == 200) { // 请求成功
        InputStream inputStream = urlConnection.getInputStream();
        // 读取结果,发送到主线程
        ...
        inputStream.close();
    }
    urlConnection.disconnect();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    完整代码

    URL url = new URL("http://blog.csdn.net/yanzhenjie1003");
    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
    urlConnection.setRequestMethod("GET");
    
    // 设置SSLSocketFoactory,这里有两种:1.需要安全证书 2.不需要安全证书;看官且往下看
    if (urlConnection instanceof HttpsURLConnection) { // 是Https请求
        SSLContext sslContext = SSLContextUtil.getSSLContext();
        if (sslContext != null) {
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
            ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslSocketFactory);
        }
    }
    
    // 设置属性
    urlConnection.setConnectTimeout(8 * 1000);
    urlConnection.setReadTimeout(8 * 1000);
    
    int responseCode = urlConnection.getResponseCode();
    if (responseCode == 200) { // 请求成功
        InputStream inputStream = urlConnection.getInputStream();
        // 读取结果,发送到主线程
        ...
        inputStream.close();
    }
    urlConnection.disconnect();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    这样就完成整个请求,其实Android请求网络就这么点代码,然后我们再写完善一点,然后封装写参数,容错什么的,就是一个小框架啦。是不是很简单呢?

    使用流行框架NoHttp怎么玩Https

      用NoHttp不要太简单,什么传参数、传文件、下载之类的,基本都是一两句话就搞定。

    Request<String> request = NoHttp.createStringRequest(url, RequestMethod.POST);
    
    // 注意这里设置SSLSokcetFactory的代码是相同的
    SSLContext sslContext = SSLContextUtil.getSSLContext();
    if (sslContext != null) {
        SSLSocketFactory socketFactory = sslContext.getSocketFactory();
        httpsRequest.setSSLSocketFactory(socketFactory);
        requestQueue.add(0, request, httpListener);//  添加到请求队列,等待接受结果
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

      我们注意到上面设置Socket的代码是相同的,剩下的就是一句话new一个请求对象就完事。是不是比原生的还要简单啊?

      这个框架叫NoHttp,是一个Android开源网络框架。 源码托管在:https://github.com/yanzhenjie/NoHttp 教程博客:http://blog.csdn.net/yanzhenjie1003

    SSLSocketFactory对象怎么来

      上面不论是纯Android代码还是NoHttp框架都用到了SSLContext,这家伙呢就是负责证书管理和信任管理器的,我们说Https可以有证书也可以没有证书,我们来看这两种情况。

    有安全证书的SSLContext

    我们把Https的证书放在assets目录下,然后通过流加载:

    public static SSLContext getSSLContext() {
        // 生成SSLContext对象
        SSLContext sslContext = SSLContext.getInstance("TLS");
        // 从assets中加载证书
        InputStream inStream = Application.getInstance().getAssets().open("srca.cer");
    
        // 证书工厂
        CertificateFactory cerFactory = CertificateFactory.getInstance("X.509");
        Certificate cer = cerFactory.generateCertificate(inStream);
    
        // 密钥库
        KeyStore kStore = KeyStore.getInstance("PKCS12");
        kStore.load(null, null);
        kStore.setCertificateEntry("trust", cer);// 加载证书到密钥库中
    
        // 密钥管理器
        KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyFactory.init(kStore, null);// 加载密钥库到管理器
    
        // 信任管理器
        TrustManagerFactory tFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tFactory.init(kStore);// 加载密钥库到信任管理器
    
        // 初始化
        sslContext.init(keyFactory.getKeyManagers(), tFactory.getTrustManagers(), new SecureRandom());
        return sslContext;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

      需要强调的是,最后一句中的new SecureRandom()在Android4.4之前的系统中有Bug。   

    修复Android系统中SecureRandom的Bug

      Android 4.4之前版本的Java加密架构(JCA)中使用的Apache Harmony 6.0M3及其之前版本的SecureRandom实现存在安全漏洞,具体位于classlib/modules/security/src/main/java/common/org/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl.java文件的engineNextBytes()方法里。当用户没有提供用于产生随机数的种子时,程序不能正确调整偏移量,导致伪随机数生成器(PRNG)生成随机序列的过程可被预测。    But值得高兴的NoHttp内部已经fix了这一bug,如果大家要自己写框架,恐怕要写很多代码去修复这个问题啦,所以推荐各位看官还是使用NoHttp。    

    没有安全证书的SSLContext

      上面看到需要需要安全证书的生成SSLContext就可以了,然后不需要证书的请求,需要两个对象,一个是SSLContext(上面已经解释过了);另一个是HostnameVerifier,顾名思义就是主机名称匹配的意思,我们看代码。

    public static SSLContext getSLLContext() {
        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType)  {}
    
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) {}
    
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }}, new SecureRandom());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sslContext;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

      就这么简单,只需要传一个null证书管理器喝一个默认的信任管理器即可。   下面再来看HostnameVerifier,既然是主机名称校验,那我们直接通过:

    private static HostnameVerifier hostnameVerifier = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

      这个怎么用呢?Android原生代码用法中,获取SSLContext的方法名不一样,多了setHostnameVerifier,其它跟有安全证书的使用一致:

    URL url = new URL("http://blog.csdn.net/yanzhenjie1003");
    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
    urlConnection.setRequestMethod("GET");
    
    // 设置SSLSocketFoactory,这里有两种:1.需要安全证书 2.不需要安全证书;看官且往下看
    if (urlConnection instanceof HttpsURLConnection) { // 是Https请求
        SSLContext sslContext = SSLContextUtil.getSSLContext();
        if (sslContext != null) {
            SSLSocketFactory sslSocketFactory = sslContext.getSLLContextNoCertificate();
            ((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslSocketFactory);
            ((HttpsURLConnection) urlConnection).setHostnameVerifier(SSLContextUtil.hostnameVerifier);
        }
    }
    
    // 设置属性
    urlConnection.setConnectTimeout(8 * 1000);
    urlConnection.setReadTimeout(8 * 1000);
    
    int responseCode = urlConnection.getResponseCode();
    if (responseCode == 200) { // 请求成功
        InputStream inputStream = urlConnection.getInputStream();
        // 读取结果,发送到主线程
        ...
        inputStream.close();
    }
    urlConnection.disconnect();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

      NoHttp用法,代码和上边的NoHttp加载证书的一样,多了一句setHostnameVerifier的:

    Request<String> request = NoHttp.createStringRequest(url, RequestMethod.POST);
    
    SSLContext sslContext = SSLContextUtil.getSSLContext();
    if (sslContext != null) {
        SSLSocketFactory socketFactory = sslContext.getSLLContextNoCertificate();
        httpsRequest.setSSLSocketFactory(socketFactory);
        httpsRequest.setHostnameVerifier(SSLContextUtil.hostnameVerifier);
        requestQueue.add(0, request, httpListener);//  添加到请求队列,等待接受结果
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果大家通读了全文,我相信已经会使用Android的Https了吧?不会的在文章下面留言喔。

  • 相关阅读:
    cesium计算当前地图范围extent以及近似当前层级zoom
    Cesium专栏-雷达遮罩动态扫描(附源码下载)
    Cesium专栏-地形开挖2-任意多边形开挖(附源码下载)
    Cesium 限制相机进入地下
    Cesium专栏-terrain地形、3dtiles模型、gltf模型 高度采样
    GeoTools介绍、环境安装、读取shp文件并显示
    基于vue+leaflet+echart的足迹分享评论平台
    10个JavaScript调试技巧,帮你更好、更快地调试代码
    后台权限管理,看这篇就够了
    编程狮-在线工具
  • 原文地址:https://www.cnblogs.com/cuihongyu3503319/p/9377516.html
Copyright © 2011-2022 走看看