android中https 双向认证

之前用的http,一切正常,自从改为https,发现好多问题,在此写了https认证的步骤以及怎么解决其中遇到的难点。

首先需要两份证书,服务器的证书ca.cer 和客户端证书client.bks。

当初给到客户端的是 client.p12,p12证书安卓也能支持。

证书有多种格式,如cer bks p12 jks, 涉及的证书转化推荐一个转化工具portecle,下载地址:https://sourceforge.net/projects/portecle/,还需要加载bcprov-jdk15on-1.59 jar包,放到C:\Program Files\Java\jre1.8.0_152\lib\ext目录。


okhttp请求的认证流程

SslOkHttpClientUtils工具类,生成OkHttpClient,执行一次即可。
public class SslOkHttpClientUtils {
    public static final String TAG = "SslOkHttpClientUtils";

    public static final String KEY_STORE_TYPE_P12 = "PKCS12";//证书类型

    private static OkHttpClient client;
    private static SSLContext sslContext;
    public static String sessionid;
    public static String cookieval;

    public static OkHttpClient getSslClient(Context context) {
        try {
            if(client == null) {
                InputStream trustKey = context.getAssets().open("ca.cer");
                InputStream clientKeyP12 = context.getAssets().open("client.p12");
                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                sslContext = SSLContext.getInstance("TLS");
                Log.d(TAG, "getSslClient: 0");
                KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
                Log.d(TAG, "getSslClient: 0.1");
                trustStore.load(null);
//                trustStore.load(trustKey, trustPassword.toCharArray());
                Log.d(TAG, "getSslClient: 1");
                trustStore.setCertificateEntry("0", certificateFactory.generateCertificate(trustKey));
                if (trustKey != null) {
                    trustKey.close();
                }
                KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
                keyStore.load(clientKeyP12, "123456".toCharArray());
              /*  KeyStore keyStore = KeyStore.getInstance("BKS");
                keyStore.load(clientKeyP12, clientPassword.toCharArray());*/
                    Log.d(TAG, "getSslClient: 2");
                    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                    trustManagerFactory.init(trustStore);
                    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
                    if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                        throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
                    }
                    X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
                    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                    keyManagerFactory.init(keyStore, "123456".toCharArray());
                    sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
                    client =  new OkHttpClient().newBuilder()
                            .sslSocketFactory(sslContext.getSocketFactory(), trustManager)
                            .followRedirects(false)
                            .followSslRedirects(false)
                            .hostnameVerifier(new HostnameVerifier() {
                                @Override
                                public boolean verify(String hostname, SSLSession session) {
                                    Log.d(TAG, "verify: "+hostname);
                                    if(hostname.equals("要加密的域名"))
                                        return true;
                                    return false;
                                }
                            })
                            .build();
                return client;
            }
            return client;
        } catch (Exception e) {
            e.printStackTrace();
            android.util.Log.d(TAG, "exception222:"+e.toString());
            return null;
        }
    }

  
}

然后选择在需要https请求的地方执行以下代码

 try {
            JSONObject result = new JSONObject();
            try {
                result.put("version", CommonUtils.getVersionName(mContext));
                result.put("system", "android");
                result.put("appType", "familys");
            } catch (JSONException e) {
                e.printStackTrace();
            }
            final  RequestBody body = RequestBody.create(MediaType.parse("application/json"), result.toString());
 
            String requestUrl = "指定的https地址";
        
            android.util.Log.d(TAG, "url: "+requestUrl+",, body:"+result.toString());
            final Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(requestUrl)
                    .client(SslOkHttpClientUtils.getSslClient(mContext))
                    .addConverterFactory(new StringConverterFactory())
                    .build();
            WebRepository repository= retrofit.create(WebRepository.class);
            retrofit2.Call data = repository.getMessage(body);
            data.enqueue(new retrofit2.Callback() {
                @Override
                public void onResponse(retrofit2.Call call, retrofit2.Response response) {
                    Log.d(TAG, "onResponse: --ok--"+response.headers());
                    Log.d(TAG, "onResponse: --ok--"+response.body());
            
                }
                @Override
                public void onFailure(retrofit2.Call call, Throwable t) {
                    Log.d(TAG, "onFailure: --err--"+t.toString());

                }
            });


        }catch (Exception ex){
            ex.printStackTrace();
            android.util.Log.d(TAG, "exception:"+ex.toString());
        } 

用的是Retrofit网络框架,对指定https地址进行网络请求,回调成功或失败的结果。

public interface WebRepository {
    @GET("/")
    Call getHtml();
    @Headers({"Content-Type: application/json","Accept: application/json"})//需要添加头
    @POST("/appconf/urlAppType")
    Call getMessage(@Body RequestBody info);
} 

总体来说安卓https认证比较简单,另一篇主要讲解webView中https的认证。

你可能感兴趣的:(anroid,https认证)