安卓中的Socket通信和Https通信中證書的校驗方法

Socket通信與Https通信

本項目demo:DEMO
下載麻煩點下小星星,謝謝!

Part1- Socket通信

socket是一個常見的網絡協議。這篇文章我們通4過個簡單的聊天室的例子,來實踐一下TCP和UDP在socket中的應用。以及使用Https協議的時候,我們客戶端所需要的操作。

在一切開始之前,需要在mainfest.xml文件中申請網絡使用權限
.
.
.

案例一:UDP聊天室

這個案例中,有兩個主要的類

  • DatagramSocket:代表UDP協議的Socket,DatagramSocket本身只是碼頭,不維護狀態,不能產生IO流,它的唯一作用就是接收和發送數據報。
  • DatagramPacket:代表數據報文,UDP傳輸過程中數據的載體

具體的細節在代碼的備註中,代碼主要分爲客戶端和服務器端,模擬進行通訊。

UDP服務器端代碼:

package com.example.chatroom.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

public class UdpServer {

    private InetAddress mAddress;//指定IP地址
    private int mPort = 7777; //用於指定監聽的端口號
    private DatagramSocket mSocket;

    private Scanner scanner;


    public static void main(String[] args) {
        System.out.println("server is started!");
        new UdpServer().start();
    }

    public UdpServer()
    {
        try {
            mAddress = InetAddress.getLocalHost();//獲取本機InetAddress實例
            mSocket = new DatagramSocket(mPort,mAddress);//構造DatagramSocket對象
            scanner = new Scanner(System.in);//獲取輸入
            scanner.useDelimiter("\n");
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (SocketException e) {
            e.printStackTrace();
        }

    }


    public void start() {
        while (true) {
            byte[] bytes = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(bytes, bytes.length);//載體
            try {
                mSocket.receive(receivePacket);//收取服務器發來的信息

                InetAddress address = receivePacket.getAddress();//獲取報文中的ip地址
                int port = receivePacket.getPort();//獲取端口號
                byte[] data = receivePacket.getData();//獲取報文中的數據
                String clientMessage = new String(data, 0, receivePacket.getLength());//用bute數組構建String對象

                System.out.println("address:" + address + "," + "port:" + port + "," + "clientMessage:" + clientMessage);

                String returnedMessage = scanner.next();//獲取控制檯的輸入
                byte[] reruened = returnedMessage.getBytes();//轉換爲byte數組

                DatagramPacket sentPacket = new DatagramPacket(reruened, reruened.length, receivePacket.getSocketAddress());//構建成數據包包
                mSocket.send(sentPacket);//發送數據報

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

UDP客戶端代碼:

package com.example.chatroom.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

public class UdpClient {

    private String mServerIp = "192.168.3.8";//指定要訪問服務的IP
    private InetAddress mInetAddress;
    private int mServerPort = 7777;//要訪問的端口號
    private DatagramSocket mSocket;
    private Scanner mScanner;

    public static void main(String[] args) {
        System.out.println("client is started!");
        new UdpClient().start();
    }

    public UdpClient()
    {
        try {
            mSocket = new DatagramSocket();
            mInetAddress = InetAddress.getByName(mServerIp);//構造InetAddress 對象
            mScanner = new Scanner(System.in);
            mScanner.useDelimiter("\n");
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    public void start()
    {
        while (true){
            try {
            String clientMessage = mScanner.next();//獲取控制檯輸入的數據

            byte[] clientMessageBytes = clientMessage.getBytes();

            DatagramPacket clientPacket = new DatagramPacket(clientMessageBytes,
                    clientMessageBytes.length,mInetAddress,mServerPort);//將數據打包到DatagramPacket 中

                mSocket.send(clientPacket);//通過socket發送數據


                byte[] bytes = new byte[1024];
                DatagramPacket serverMsgPacket = new DatagramPacket(bytes,bytes.length);
                mSocket.receive(serverMsgPacket);//接收服務器發來的數據



//                InetAddress address = serverMsgPacket.getAddress();
//                int port = serverMsgPacket.getPort();
                byte[] data = serverMsgPacket.getData();
                String serverMessage = new String(data, 0, serverMsgPacket.getLength());

                System.out.println( "serverMessage:" + serverMessage);//將數據打印在控制檯

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

測試結果如下:

在這裏插入圖片描述
在這裏插入圖片描述
值得注意的是, mSocket.receive()方法在沒有收到數據的時候會一直處於阻塞狀態。

我們可以以將客戶端的代碼遷移到安卓上,佈局如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".UDPActivity">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="50dp">


    <EditText
        android:id="@+id/input"
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
        <Button
            android:id="@+id/send"
            android:text="發送"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"/>
    </LinearLayout>
    <ScrollView
        android:layout_marginTop="50dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/message"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>


    </ScrollView>

</RelativeLayout>

就是這個樣子的:
在這裏插入圖片描述
遷移之後,安卓端代碼如下:
首先我們將消息發送的業務邏輯遷移到一個新的類中,代碼和之前客戶端的基本一致:

package com.example.chatroom.biz;

import android.os.Handler;
import android.os.Looper;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class UdpClientBiz {

    private String mServerIp = "192.168.2.101";
    private InetAddress mInetAddress;
    private int mServerPort = 7777;
    private DatagramSocket mSocket;

    private Handler mUIHandler = new Handler(Looper.getMainLooper());//將handler聲明在主線程中,方便我們操作UI

//創建一個接口在進行收到消息和發生異常時候的回調
    public interface OnMessageReturnListener
    {
        void onMessageReturn(String message);
        void onError(Exception e);

    }

    public void sendMsg(final String msg, final OnMessageReturnListener onMessageReturnListener)
    {
        new Thread(){
            @Override
            public void run() {
                try {
                    //sendmessage
                    byte[] clientMessageBytes = msg.getBytes();

                    DatagramPacket clientPacket = new DatagramPacket(clientMessageBytes,
                            clientMessageBytes.length,mInetAddress,mServerPort);
                    mSocket.send(clientPacket);

                    //reciveMessage
                    byte[] bytes = new byte[1024];
                    DatagramPacket serverMsgPacket = new DatagramPacket(bytes,bytes.length);
                    mSocket.receive(serverMsgPacket);
                    final String serverMessage = new String(serverMsgPacket.getData(), 0, serverMsgPacket.getLength());

                    mUIHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            onMessageReturnListener.onMessageReturn(serverMessage);
                        }
                    });


                    System.out.println( "clientMessage:" + serverMessage);
                } catch (final IOException e) {
                    e.printStackTrace();
                    mUIHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            onMessageReturnListener.onError(e);
                        }
                    });

                }
            }
        }.start();

    }

    public UdpClientBiz()
    {
        try {
            mSocket = new DatagramSocket();
            mInetAddress = InetAddress.getByName(mServerIp);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }


    public void destory()
    {
        if (mSocket != null)
        {
            mSocket.close();
        }
    }

}

在Activity中:

package com.example.chatroom;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.chatroom.biz.UdpClientBiz;

public class UDPActivity extends AppCompatActivity  {
    private EditText mEditText;
    private Button mButtonSend;
    private TextView mTextViewMessage;

    private UdpClientBiz udpClientBiz = new UdpClientBiz();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle("UDP_CHATROOM");

        initView();

        mButtonSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                String messages = mEditText.getText().toString();
                if (TextUtils.isEmpty(messages))
                {
                    return;
                }
                appendMessage2Content("client:"+messages);
                udpClientBiz.sendMsg(messages, new UdpClientBiz.OnMessageReturnListener() {
                    @Override
                    public void onMessageReturn(String message) {
                        appendMessage2Content("server:"+message);
                    }

                    @Override
                    public void onError(Exception e) {
                        e.printStackTrace();
                    }
                });
                mEditText.setText(" ");

            }
        });
    }

    private void appendMessage2Content(String message) {
        mTextViewMessage.append(message+"\n");
    }

    private void initView() {
        mEditText = findViewById(R.id.input);
        mButtonSend = findViewById(R.id.send);
        mTextViewMessage = findViewById(R.id.message);
    }


}


結果如下:
在這裏插入圖片描述

案例二:TCP聊天室

相比UDP而言,TCP就顯得比較簡潔。我們只需要通過ServerSocket的輸入流/輸出流來獲取客戶端/服務器發來的數據。
雖然比較簡潔,但我們的這個例子卻不太簡單。這個案例實現的是多個客戶端和服務器組成的多人聊天室。由於聊天室不是1對1的,所以需要一個消息緩存的機制,然後讓服務器循環從消息池中取出消息,轉發到客戶端。

我們先看消息池是怎麼樣的:

package com.example.chatroom.tcp.server;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;

public class MessagePool {

    private static MessagePool messagePoolInstance = new MessagePool();//單例
    private LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue();//消息隊列
    private List<MessageConmingListener> msgListeners = new ArrayList<>();


    public MessagePool() {
    }



//獲取單例,爲例簡單先不做鎖
    public static MessagePool getMessagePoolInstance()
    {
        return messagePoolInstance;
    }

//發送消息的方法
    public void sendMessage(String message)
    {
        try {
            messageQueue.put(message);//將消息放入消息隊列
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void start()
    {
        new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        String msg = messageQueue.take();//從消息隊列中取出消息
                        notifiMessageComing(msg);//使用觀察者模式,通知客戶端新消息
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        }.start();
    }

//通知客戶端新的消息
    private void notifiMessageComing(String msg) {
        for (MessageConmingListener listener:msgListeners) {
            listener.onMessageComing(msg);
        }
    }

//消息監聽器接口
    public interface MessageConmingListener
    {
        void onMessageComing(String message);
    }

//註冊消息監聽器
    public void addMessageConmingListener(MessageConmingListener messageConmingListener)
    {
        msgListeners.add(messageConmingListener);
    }
}

然後我們看服務器端:

package com.example.chatroom.tcp.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer {

    public void start() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(9090);//監聽9090端口
            MessagePool.getMessagePoolInstance().start();//開始從消息池中取出消息,並發出去
            while (true) {
                Socket socket = serverSocket.accept();//接收客戶端的請求,並拿到存儲了客戶端數據的Socket對象
                System.out.println("ip:" + socket.getInetAddress().getHostAddress()
                        + ", port:" + socket.getPort() + "is online now ...");

                ClientTask clientTask = new ClientTask(socket);//給這個socket所代表的客戶端註冊一個ClientTask 
                MessagePool.getMessagePoolInstance().addMessageConmingListener(clientTask);//將ClientTask 加入到觀察者中
                clientTask.start();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new TCPServer().start();
    }
}

我們看看clientTask:

package com.example.chatroom.tcp.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

//實現了消息監聽的接口,繼承自Thread類
public class ClientTask extends Thread implements MessagePool.MessageConmingListener {

    private Socket mSocket;
    private InputStream inputStream;
    private OutputStream outputStream;

    public ClientTask(Socket Socket) {

        try {
            mSocket = Socket;
            inputStream = mSocket.getInputStream();
            outputStream = mSocket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void run() {
        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));//用BufferReader從輸入流中讀取數據
        try {
            String line ;

            while ((line = br.readLine())!=null)
            {
                System.out.println("read:"+line);
                //轉發消息給其他客戶端
                MessagePool.getMessagePoolInstance().sendMessage("port:"+mSocket.getPort()+"  message:"+line);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

//在消息池中被回調
    @Override
    public void onMessageComing(String message) {
        try {
        //向連接到服務的客戶端寫數據
            outputStream.write(message.getBytes());
            outputStream.write("\n".getBytes());
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

最後我們看一下客戶端類:

package com.example.chatroom.tcp.client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

public class TCPClient {


    private Scanner mScanner;

    public TCPClient() {
        this.mScanner = new Scanner(System.in);
        mScanner.useDelimiter("\n");
    }

    public void start()
    {
        try {
            Socket socket = new Socket("192.168.2.100",9090);//訪問對應ip下的端口
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();

            final BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));

            new Thread(){
                @Override
                public void run() {
                    String line = null;
                    try {

                        while ((line = br.readLine()) != null) {

                            System.out.println(line);//將受到的消息打印到控制檯
                        }
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }.start();


            while (true)
            {
            //將控制檯輸入的消息發送到服務器
                String msg =  mScanner.next();
                bw.write(msg);
                bw.newLine();
                bw.flush();

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new TCPClient().start();
    }
}

效果如下:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
我們可以在對應的socket做一些標識,例如暱稱什麼的,然後就可以得到和真正的聊天類似的效果。

然後我們將這個功能遷移帶客戶端:
我們新建一個業務類,將客戶端中帶部分代碼分割出去:

package com.example.chatroom.biz;

import android.os.Handler;
import android.os.Looper;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class TCPClientBiz {
    private Socket socket ;
    private InputStream inputStream ;
    private OutputStream outputStream ;

    private Handler mUIHandler = new Handler(Looper.getMainLooper());


    private  OnMsgReceiveListener mListener;

    public void setOnMsgReceiveListener(OnMsgReceiveListener onMsgReceiveListener) {
        mListener = onMsgReceiveListener;
    }

    public TCPClientBiz() {

        new Thread() {
            @Override
            public void run() {
                try {
                    socket= new Socket("192.168.2.101",9090);
                    inputStream = socket.getInputStream();
                    outputStream = socket.getOutputStream();

                    readServerMsg();
                }
                catch (final Exception e)
                {
                    mUIHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (mListener !=null) {
                                mListener.onError(e);
                            }
                        }
                    });
                    e.printStackTrace();
                }
            }
        }.start();

    }

    public void sendMessage(final String msg ) {
        new Thread() {
            @Override
            public void run() {
                try {
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
                    bw.write(msg);
                    bw.newLine();
                    bw.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    private void readServerMsg() throws IOException {
         BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
        String line = null;
        while ((line = br.readLine()) != null) {
            final String finalLine = line;
            mUIHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (mListener !=null) {
                        mListener.onMessageReceived(finalLine);
                    }
                }
            });

        }
    }

    public interface OnMsgReceiveListener
    {
        void onMessageReceived(String msg);
        void onError(Exception e);
    }

    public void onDestory()
    {

        try {
            if (socket!=null)
            {
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if (inputStream !=null)
            {
                inputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if (outputStream != null)
            {
                outputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

然後是Activity的代碼:

package com.example.client;


import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.example.chatroom.biz.TCPClientBiz;

public class TCPActivity extends AppCompatActivity  {
    private EditText mEditText;
    private Button mButtonSend;
    private TextView mTextViewMessage;

    private TCPClientBiz tcpClientbiz;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_t_c_p);
        tcpClientbiz = new TCPClientBiz();
        tcpClientbiz.setOnMsgReceiveListener(new TCPClientBiz.OnMsgReceiveListener() {
            @Override
            public void onMessageReceived(String msg) {
                appendMessage2Content(msg);//將受到的消息放在textview中
            }

            @Override
            public void onError(Exception e) {

            }
        });

        initView();

        mButtonSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTextViewMessage.setText(" ");
                String messages = mEditText.getText().toString();
                if (TextUtils.isEmpty(messages))
                {
                    return;
                }
                appendMessage2Content("client:"+messages);
                tcpClientbiz.sendMessage(messages);

            }
        });
    }

    private void appendMessage2Content(String message) {
        mTextViewMessage.append(message+"\n");
    }

    private void initView() {
        mEditText = findViewById(R.id.input);
        mButtonSend = findViewById(R.id.send);
        mTextViewMessage = findViewById(R.id.message);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        tcpClientbiz.onDestory();
    }
}

在這裏插入圖片描述
這裏需要注意的是,要將客戶端的代碼放在另外一個module 中,不然會運行不起來。

Part2-Https通信

Https是是一種採用了加密算法的通訊協議。爲了安全起見,在安卓端訪問使用了Https協議的服務的時候(服務並未獲得CA證書)需要校驗證書以及域名,來保證數據的安全性。

案例三:證書校驗以及域名校驗
我們先寫一個Utils來訪問一個鏈接:

package https;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
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.TrustManager;
import javax.net.ssl.TrustManagerFactory;

public class HttpUtils {

    private static Handler mUIHandler = new Handler(Looper.getMainLooper());
    public interface HttpListener
    {
        void onSucceed(String content);
        void onFailed(Exception e);
    }

    public static void doGet(final Context context,final String urlStr, final HttpListener httpListener)
    {
        new Thread()
        {
            @Override
            public void run() {

                InputStream inputStream = null;
                try {
                    URL url = new URL(urlStr);
                    HttpsURLConnection httpConn = (HttpsURLConnection) url.openConnection();



                    //校驗證書_方法1:
                    X509Certificate certificate = getCert(context);
                    TrustManager[] tm = {new MyX509TrustManager(certificate)};
                    SSLContext sslContext = SSLContext.getInstance("TLS");
                   

                    //校驗證書_方法2:
                    String keyStoreType = KeyStore.getDefaultType();
                    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
                    keyStore.load(null);
                    keyStore.setCertificateEntry("srca",certificate);

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

                    trustManagerFactory.init(keyStore);

                    TrustManager[] tm1 = trustManagerFactory.getTrustManagers();


//在獲取了TrustManager[]數組之後的步驟就相同了

                    sslContext.init(null,tm,new SecureRandom());
                    httpConn.setSSLSocketFactory(sslContext.getSocketFactory());

                    //校驗域名
                    httpConn.setHostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {

                            HostnameVerifier defaultHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
                            return defaultHostnameVerifier.verify("12306.cn",session);



                        }
                    });


                    httpConn.setDoInput(true);
                    httpConn.setDoOutput(true);
                    httpConn.setRequestMethod("GET");
                    httpConn.setConnectTimeout(5*1000);
                    httpConn.setReadTimeout(5*1000);
                    httpConn.connect();

                    final StringBuilder content = new StringBuilder();
                    inputStream = httpConn.getInputStream();
                    byte[] buf  = new byte[2048];
                    int len = -1;
                    while ((len = inputStream.read(buf))!=-1)
                    {
                        content.append(new String(buf,0,len));
                    }
                    mUIHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            httpListener.onSucceed(content.toString());
                        }
                    });

                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    httpListener.onFailed(e);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (KeyManagementException e) {
                    e.printStackTrace();
                } catch (KeyStoreException e) {
                    e.printStackTrace();
                } catch (CertificateException e) {
                    e.printStackTrace();
                } finally {
                    if (inputStream!=null)
                    {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }.start();

    }

    private static X509Certificate getCert(Context context) {

        try {
            InputStream inputStream = context.getAssets().open("xxx.cer");//在本地assets目錄下保存的網站證書
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
             return (X509Certificate) certificateFactory.generateCertificate(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        }
        return null;
    }
}


其中,MyX509TrustManager類爲:

package https;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class MyX509TrustManager implements X509TrustManager {

    private X509Certificate mySeverCert;

    public MyX509TrustManager(X509Certificate mySeverCert) {
        this.mySeverCert = mySeverCert;
    }

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

    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        for (X509Certificate certificate : chain)
        {
            //證書是否過期以及合法性校驗
            certificate.checkValidity();

            try {
                certificate.verify(mySeverCert.getPublicKey());
            } catch (Exception e) {
            //出現錯誤代表證書驗證失敗
               throw new CertificateException(e);
            }
        }

    }

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

證書校驗的兩種方法,第一種需要我們自己去校驗,第二種是調用API爲我們校驗。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章