[JAVA] Utiliser le certificat pfx avec Okhttp3

Historique des postscript

08/02/2020 Ajout du lien de référence 2020/02/10 Ajout de la raison de son utilisation asynchrone

introduction

Conservez le code que vous avez écrit lorsque vous avez décidé de prendre en charge la communication HTTPS en utilisant le certificat client comme mémo au cas où vous quittez l'entreprise et ne pouvez pas voir le code source La raison pour laquelle je m'en tiens à Okhttp est que je l'ai détesté parce que j'ai souffert il y a longtemps. Http (s) URLConnection Il peut y avoir des parties qui sont mal écrites et d'autres qui ressemblent à une prédication à la personne active, mais pardonnez-moi, c'est un mémo pour moi, donc c'est différent!

Préparation préalable

  1. Créez un dossier "assets" sous main (même niveau que main et res)
  2. Stockez le certificat pfx dans le dossier assets (cette fois, pour plus de commodité, utilisez "hogehage.pfx")
  3. Ajoutez l'autorisation de communication Internet à "AndroidManifest.xml" (↓ comme ça) Il n'y a pas de problème si la place supplémentaire est entre les manifestes, mais n'écrivez pas entre les activités
<manifeste ・ ・ ・
...
//Autorisations pour la connexion Internet
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
  1. Ajoutez ce qui suit à la partie "dépendances" de "build.gradle (sous app)" La version est le 05/02/2020 Vérifiez la partie "Releases" de https://square.github.io/okhttp/ pour voir s'il s'agit de la dernière

build.gradle


・ ・ ・
dependencies {
・ ・ ・
implementation("com.squareup.okhttp3:okhttp:4.3.1")

1 et 2 sont pour la communication HTTPS, 3 et 4 sont pour Okhttp Ça devient de plus en plus difficile d'écrire jusqu'à présent ... FE Fukayuki 〇 Je veux le faire

code

Asynctask, pas le thread principal ... J'écris dans un traitement dit asynchrone J'écrivais dans le fil principal (MainActivity, etc.), mais ... ça? Pourquoi l'avez-vous changé? → À l'origine, Asynctask utilisait une connexion Httpurl. J'ai essayé d'utiliser okhttp de manière asynchrone et c'était possible, et le fonctionnement de l'application semble être plus léger, donc je l'ai adopté tel quel (note supplémentaire)

AsyncHttps.java


package com.example.test;

import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

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

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

//Traitement asynchrone
//Un lieu de communication HTTPS
//L'appelant a converti l'image en un tableau d'octets et l'a passé à cet acte
public class AsyncHttps extends AsyncTask<byte[], Void, String>
{

    private Context mContext;
    public AsyncHttps(Context context)
    {mContext = context;}

    public static String res=null;

    final Handler handler = new Handler();
    //Pour les numéros de tableau dans URLsList
    public static int url_id = 0;

    //Variable de stockage des résultats de communication
    public static String result = null;

    //Traitement asynchrone
    @Override
    protected String doInBackground(byte[]... params)
    {

        //J'ai réalisé que je devais écrire la liste d'url dans un autre acte comme un tableau et envoyer le numéro du tableau à la source.
        String urlSt = URLsList.URL[url_id];

        byte[] word = params[0];

	//
        return result;
    }


    //Pour la communication http
    public void http_post(byte[] bytes)
    {
        //Cela semble être un paramètre pour l'envoi en utilisant JSON
	//MediaType doit être modifié en fonction de ce que vous envoyez(Si c'est une image"image/jpg"Se sentir comme)
        MediaType mediaType= MediaType.parse("application/json; charset=utf-8");
        //Demande de création de corps. Choses à envoyer
        RequestBody requestBody = RequestBody.create(mediaType,bytes);
        //C'est comme faire une demande et emballer le courrier, non?(Texto)
        Request request = new Request.Builder()
                //Destination
                .url(URLsList.URL[url_id])
                .post(requestBody)      //Contenu à envoyer
                .build();               //Construisez ces


        KeyManagerFactory keyManagerFactory;
        //Mot de passe défini lors de la création du certificat
        final char[] PASSWORD = "***Mot de passe ici***".toCharArray();
        InputStream inputStream;
        TrustManagerFactory trustManagerFactory;
        SSLSocketFactory sslSocketFactory;
        X509TrustManager trustManager;
        try
        {
            //Spécification du fichier de certificat client(Placez-le dans le dossier des actifs)
            inputStream = mContext.getResources().getAssets().open("hogehage.pfx");
            //À titre de référence, cette extension était p12, n'est-ce pas le cas?
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            //À partir de maintenant, vous pouvez copier et coller sans penser à rien
            keyStore.load(inputStream,PASSWORD);
            trustManagerFactory = TrustManagerFactory.getInstance
                    (TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager))
            {
                throw new IllegalStateException("Unexpected default trust managers:"
                        + Arrays.toString(trustManagers));
            }
            trustManager = (X509TrustManager)trustManagers[0];

            keyManagerFactory = KeyManagerFactory.getInstance("X509");
            keyManagerFactory.init(keyStore,PASSWORD);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(keyManagerFactory.getKeyManagers(),null,null);
            sslSocketFactory = sslContext.getSocketFactory();
            //Copiez et collez jusqu'à présent

            final OkHttpClient client = new OkHttpClient.Builder()
                    //.connectTimeout(10, TimeUnit.SECONDS)	//Délai d'expiration 3 tireur
                    //.readTimeout(10, TimeUnit.SECONDS)	//Je ne sais pas ce que tu mets
                    //.writeTimeout(10, TimeUnit.SECONDS)	//À plus tard
                    .sslSocketFactory(sslSocketFactory,trustManager)
                    .build();

            client.newCall(request).enqueue(new Callback()
            {
                @Override
                public void onFailure(@NonNull Call call, IOException e)
                {
                    //Il semble que le traitement lorsqu'une exception se produit sera stable s'il est traité séparément.
                    failMessage();
                    e.printStackTrace();
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException
                {
                    result = String.valueOf(response);
                    //Si quelque chose revient, je peux ou non faire quelque chose ici
                    client.connectionPool().evictAll();
                }
            });
        }catch (IOException e)//Si quelque chose explose en dessous, il apparaîtra dans le journal de l'onglet Erreur. Il n'y a rien à toucher.
        {Log.e("contenu de l'erreur:", String.valueOf(e));}
        catch (NoSuchAlgorithmException e)
        {Log.e("contenu de l'erreur:", String.valueOf(e));}
        catch (CertificateException e)
        {Log.e("contenu de l'erreur:", String.valueOf(e));}
        catch (UnrecoverableKeyException e) 
        {Log.e("contenu de l'erreur:", String.valueOf(e));}
        catch (KeyStoreException e) 
        {Log.e("contenu de l'erreur:", String.valueOf(e));}
        catch (KeyManagementException e) 
        {Log.e("contenu de l'erreur:", String.valueOf(e));}
    }

    //Lorsqu'une exception se produit(Quand quelque chose ne va pas)En traitement
    private void failMessage()
    {Log.d("Résultat de la communication:","C'était mauvais…");}

}

référence

Okhttp officiel: https://square.github.io/okhttp/ Authentification du certificat client dans l'application Android: https://qiita.com/c_ume/items/d082ffd20b3316aab805 Now that SSLSocketFactory is deprecated on Android, what would be the best way to handle Client Certificate Authentication? https://stackoverflow.com/questions/31002159/now-that-sslsocketfactory-is-deprecated-on-android-what-would-be-the-best-way-t

Recommended Posts

Utiliser le certificat pfx avec Okhttp3
Utiliser ProGuard avec Gradle
Utiliser Puphpeteer avec Docker
Utilisez XVim2 avec Xcode 12.0.1
Utilisation de CentOS avec LXD
Utiliser Webmock avec Rspec
Utiliser les WebJars avec Gradle
Utilisez jlink avec gradle
Utiliser des couches Lambda avec Java
Utiliser GDAL avec Python avec Docker
Utiliser Thymeleaf avec Azure Functions
Utiliser l'API Bulk avec RestHighLevelClient
Utilisez SDKMAN! Avec Git Bash
Utilisez plusieurs bases de données avec Rails 6.0
Utiliser Spring JDBC avec Spring Boot
Utilisez Ruby avec Google Colab
Utiliser SpatiaLite avec Java / JDBC
Utilisez log4j2 avec YAML + Gradle
[Docker] À utiliser à tout moment avec Docker + Rails
Utiliser PlantUML avec Visual Studio Code
Utiliser l'authentification de base avec Spring Boot
Utiliser java avec MSYS et Cygwin
Utiliser le constructeur avec des arguments dans cucumber-picocontainer
Utiliser Microsoft Graph avec Java standard
Utiliser le type inet PostgreSQL avec DbUnit
Utilisez bootstrap 4 avec PlayFramework 2.6 (pas de CDN)
Utiliser Git avec SourceTree et Eclipse
Utiliser Azure Bing SpellCheck avec Java
Utilisez JDBC avec Java et Scala.
Utiliser DataDog APM avec des frameworks non pris en charge
Utiliser Java 11 avec Google Cloud Functions
Comment utiliser mssql-tools avec Alpine
À partir de Spring Boot 0. Utilisez Spring CLI
Utilisation de cuda11.0 avec pytorch en utilisant Docker