2

HTTPS経由でサーバーに接続する必要があるAndroidアプリケーションを作成しています。私が試した最初の解決策はこれでした:(セキュリティ上の欠陥を気にしないでください)

final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
};
private static void trustAllHosts() {
    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return new java.security.cert.X509Certificate[] {};
        }

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

        public void checkServerTrusted(X509Certificate[] chain,
                String authType) throws CertificateException {
        }
    } };

    // Install the all-trusting trust manager
    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
             HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
        Log.d("USR_SSL", e.getMessage());
    }
}
//...

@Override
protected String doInBackground(String... params) {
    try {

        URL url = new URL(params[0]);
                    //This is an HTTPS url
        String jsonStr = "";
        if(params.length > 1) {
            jsonStr = params[1];
        }
        HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection();
        trustAllHosts();
        urlConn.setHostnameVerifier(DO_NOT_VERIFY);
        urlConn.setRequestProperty("Content-Type", "application/json");
        urlConn.setRequestProperty("Accept", "application/json");
        urlConn.setRequestMethod("POST");

        OutputStream os = urlConn.getOutputStream();
        os.write(jsonStr.getBytes());
        os.flush();
//...

認証、セッション、その他すべての優れた機能も使用する必要があることに気付くまでは、(ほぼ)すべてうまくいきました。以下を使用して本当に問題がなかったはずです。

CookieManager cookieManager = new CookieManager();  
CookieHandler.setDefault(cookieManager);

ただし、残念ながら、Android APIレベル8をサポートする必要があります。つまり、上記の2行のコードは機能しません。それを踏まえて、私は数時間インターネットを調べて、HTTPSとCookieの両方をサポートしているように見えるApacheクラスを使用してソリューションを構築しようとしました。

これは私がなんとか一緒に縫うことができたコードです:

public class ConnectionMediator {
public class MySSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        sslContext.init(null, new TrustManager[] { tm }, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}
public void tryConnect(String url, String data) {
    try {
        //SSL Stuff
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);

        SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        DefaultHttpClient httpClient = new  DefaultHttpClient(ccm, params);

        //Cookie stuff
        HttpContext localContext = new BasicHttpContext();
        HttpResponse response = null;
        HttpPost httpPost = null;
        StringEntity tmp = null;

        httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);
        httpPost = new HttpPost(url);

        tmp = new StringEntity(data,"UTF-8");
        httpPost.setEntity(tmp);

        response = httpClient.execute(httpPost,localContext);
    } catch(Exception e) {
        Log.d("USR_DEBUG", e.getClass().toString() + ": " + e.getMessage());
    }

}
}

これを書いている時点で、私はを取得しますNetworkOnMainThreadExceptionが、これはかなり重要ではありません。重要なことと私が指摘したいことは、HTTPSを使用して接続し、Cookieを使用する場合のように、自分が何をしているのかわからないということです。これまで聞いたことのない13の異なるクラスを使用する必要があります。の。明らかに、HTTPS / Javaネットクラスに関する私の知識はnullに隣接していますが、それにもかかわらず、私はもっと直感的な何かを期待していました。したがって、「これは機能しない」タイプの質問ではなく、「何をすべきか」、または「どうすれば自分がしなければならないことを学ぶことができるか」という質問になります。

どうもありがとうございます、

非常に混乱したコーダー

4

1 に答える 1

2

私の最初の質問には2つの部分がありました。1つはHTTPSの使用方法、もう1つはCookieを一緒に使用する方法です。

私の質問は、すでに部分的に答えていたので、十分に徹底的ではありませんでした-最初に投稿したコードはHTTPSに関して機能しNetworkOnMainThreadException、たとえば、を使用して別のスレッドでコードを実行していなかったために発生しましたAsyncTask

ただし、Cookieを適切に使用するには、次のようなソリューションを使用する必要があります。

public class State {
    private static HttpContext httpContext;
    public static HttpContext getHttpContext() {
        if(httpContext == null) {
            httpContext = new BasicHttpContext();
            CookieStore cookieStore = getCookieStore();
            httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
        }
        return httpContext;
    }
    private static CookieStore cookieStore;
    public static CookieStore getCookieStore() {
        if(cookieStore == null) {
            cookieStore = new BasicCookieStore();
        }
        return cookieStore;
    }
}

これが(静的クラスを使用して)それを行う「Android」の方法であるかどうかはわかりませんが、機能します:

    //...
    //Connection objects
    DefaultHttpClient httpClient = new DefaultHttpClient(ccm, params);
    HttpPost httpPost = null;

    //Cookie stuff
    HttpContext httpContext = State.getHttpContext();
    httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);
    //....

HttpClient同じものが使用されている場合、毎回別のものを使用するCookieStoreとセッションが保持されるようHttpContextです。この答えは「物事はうまくいく」(私が今必要としているものです)が、すべてをつなぐために10以上のクラスが必要な理由をまったく説明していないため、完全な答えではありません。

于 2012-10-30T08:45:07.000 に答える