2013-05-05 61 views
5

tôi có phương pháp này:Thay đổi HTTP bài yêu cầu HTTPS bài yêu cầu:

public static String getReportMetadata (String reportId, String sessionId, String url) throws Exception{ 

    Map<String, Object> jsonValues = new HashMap<String, Object>(); 
    jsonValues.put("reportID", reportId); 
    jsonValues.put("sessionID", sessionId); 
    JSONObject json = new JSONObject(jsonValues); 

    DefaultHttpClient client = new DefaultHttpClient(); 

    HttpPost post = new HttpPost(url + GET_REPORT_METADATA_ACTION); 

    AbstractHttpEntity entity = new ByteArrayEntity(json.toString().getBytes("UTF8")); 
    entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json")); 
    post.setEntity(entity);   
    HttpResponse response = client.execute(post); 

    return getContent(response);    
} 

rằng thực hiện một bài yêu cầu HTTP mà of-Tất nhiên tôi chạy bằng AsyncTask để lấy dữ liệu từ máy chủ.

Câu hỏi của tôi: có thể một số một xin vui lòng giải thích cho tôi một cách đơn giản các bước tôi cần phải thực hiện để thay đổi loại kết nối này cho một kết nối an toàn (còn được gọi bằng HTTPS) là gì. Chỉ từ quan điểm android (nghĩa là ứng dụng khách).

CẬP NHẬT: Như đã đề xuất, tôi đã cố gắng chỉ thay đổi liên kết và thêm https thay vì http nhưng không trả lại câu trả lời. Như tôi hiểu rằng tôi không cần phải nhận được và lưu trữ một chứng chỉ tự đăng nhập để kết nối với phía máy chủ

UPDATE2: Các giải pháp mà làm việc cho tôi:

EasySSLSocketFactory:

public class EasySSLSocketFactory implements SocketFactory, LayeredSocketFactory { 

private SSLContext sslcontext = null; 

private static SSLContext createEasySSLContext() throws IOException { 
    try { 
     SSLContext context = SSLContext.getInstance("TLS"); 
     context.init(null, new TrustManager[] { new EasyX509TrustManager(null) }, null); 
     return context; 
    } catch (Exception e) { 
     throw new IOException(e.getMessage()); 
    } 
} 

private SSLContext getSSLContext() throws IOException { 
    if (this.sslcontext == null) { 
     this.sslcontext = createEasySSLContext(); 
    } 
    return this.sslcontext; 
} 

/** 
* @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket, java.lang.String, int, 
*  java.net.InetAddress, int, org.apache.http.params.HttpParams) 
*/ 
public Socket connectSocket(Socket sock, String host, int port, InetAddress localAddress, int localPort, 
     HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException { 
    int connTimeout = HttpConnectionParams.getConnectionTimeout(params); 
    int soTimeout = HttpConnectionParams.getSoTimeout(params); 
    InetSocketAddress remoteAddress = new InetSocketAddress(host, port); 
    SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket()); 

    if ((localAddress != null) || (localPort > 0)) { 
     // we need to bind explicitly 
     if (localPort < 0) { 
      localPort = 0; // indicates "any" 
     } 
     InetSocketAddress isa = new InetSocketAddress(localAddress, localPort); 
     sslsock.bind(isa); 
    } 

    sslsock.connect(remoteAddress, connTimeout); 
    sslsock.setSoTimeout(soTimeout); 
    return sslsock; 

} 

/** 
* @see org.apache.http.conn.scheme.SocketFactory#createSocket() 
*/ 
public Socket createSocket() throws IOException { 
    return getSSLContext().getSocketFactory().createSocket(); 
} 

/** 
* @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket) 
*/ 
public boolean isSecure(Socket socket) throws IllegalArgumentException { 
    return true; 
} 

/** 
* @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, java.lang.String, int, 
*  boolean) 
*/ 
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, 
     UnknownHostException { 
    return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); 
} 

// ------------------------------------------------------------------- 
// javadoc in org.apache.http.conn.scheme.SocketFactory says : 
// Both Object.equals() and Object.hashCode() must be overridden 
// for the correct operation of some connection managers 
// ------------------------------------------------------------------- 

public boolean equals(Object obj) { 
    return ((obj != null) && obj.getClass().equals(EasySSLSocketFactory.class)); 
} 

public int hashCode() { 
    return EasySSLSocketFactory.class.hashCode(); 
} 
} 

EasyX509TrustManager:

public class EasyX509TrustManager implements X509TrustManager { 

private X509TrustManager standardTrustManager = null; 

/** 
* Constructor for EasyX509TrustManager. 
*/ 
public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException { 
    super(); 
    TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
    factory.init(keystore); 
    TrustManager[] trustmanagers = factory.getTrustManagers(); 
    if (trustmanagers.length == 0) { 
     throw new NoSuchAlgorithmException("no trust manager found"); 
    } 
    this.standardTrustManager = (X509TrustManager) trustmanagers[0]; 
} 

/** 
* @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType) 
*/ 
public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException { 
    standardTrustManager.checkClientTrusted(certificates, authType); 
} 

/** 
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType) 
*/ 
public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException { 
    if ((certificates != null) && (certificates.length == 1)) { 
     certificates[0].checkValidity(); 
    } else { 
     standardTrustManager.checkServerTrusted(certificates, authType); 
    } 
} 

/** 
* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() 
*/ 
public X509Certificate[] getAcceptedIssuers() { 
    return this.standardTrustManager.getAcceptedIssuers(); 
} 
} 

Và tôi đã thêm phương pháp này: getNewHttpClient()

public static HttpClient getNewHttpClient() { 
    try { 
     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); 

     return new DefaultHttpClient(ccm, params); 
    } catch (Exception e) { 
     return new DefaultHttpClient(); 
    } 
} 

Cuối cùng cho mọi nơi trong mã của tôi rằng tôi đã có:

DefaultHttpClient client = new DefaultHttpClient(); 

tôi thay thế nó bằng:

HttpClient client = getNewHttpClient(); 

Tôi hiện có thể nhận dữ liệu từ phía máy chủ, câu hỏi cuối cùng là: là những gì tôi đã làm là an toàn không? hoặc nó chấp nhận từng chứng chỉ tự ký? nếu đây là trường hợp cần phải làm gì để thay đổi nó?

Mọi trợ giúp sẽ được đánh giá cao.

+0

Có lẽ javadoc sẽ giúp bạn: [SchemeRegistry] (http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/scheme/SchemeRegistry.html) [SSLSocketFactory] (http: //hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/conn/ssl/SSLSocketFactory.html) – mleczey

+1

Theo [Hướng dẫn SSL HTTPClient] (htt p: //hc.apache.org/httpclient-legacy/sslguide.html), thực sự điều duy nhất bạn cần làm là đặt "https: //" vào chuỗi URL của bạn. Điều này sẽ cung cấp cho bạn kết nối HTTPS với cấp xác thực tương đương với trình duyệt (nghĩa là bất kỳ một trong số hàng trăm CA nào cũng có thể ký chứng chỉ máy chủ). Các 'SchemeRegistry' và' SSLSocketFactory' chỉ đi vào chơi nếu bạn muốn tùy chỉnh xử lý SSL, thường là để thực hiện SSL pinning (có nghĩa là, sử dụng một ràng buộc xác thực mạnh mẽ hơn). Hãy xem github của Moxie để có được một bộ pin ssl Android (LGPL được cấp phép). – Barend

+0

@Bây giờ, tôi đã cố gắng chỉ thay đổi liên kết và thêm https thay vì http nhưng không trả lại câu trả lời. Theo tôi hiểu tôi cần phải nhận và lưu trữ chứng chỉ tự ký để kết nối với phía máy chủ. –

Trả lời

5

Từ số Apache HttpClient SSL guide:

truyền thông HTTP an toàn qua SSL phải đơn giản như giao tiếp HTTP đơn giản.

Vì vậy, bạn chỉ đơn giản là nên thay đổi http: // XXXX để https: // XXXX

EDIT: Tôi vừa mới nhìn thấy câu trả lời @Barend 's đó là hoàn chỉnh hơn

+0

Tôi đã cố gắng chỉ thay đổi liên kết và thêm https thay vì http nhưng nó không trả lại câu trả lời. Theo tôi hiểu, tôi cần có chứng chỉ tự ký để kết nối với phía máy chủ. –

+0

Nếu máy chủ có chứng chỉ tự ký, bạn cần phải thông báo cho HttpClient của mình để chấp nhận nó. Nếu bạn muốn làm điều này, bạn có thể xem tại đây http://stackoverflow.com/questions/1217141/self-signed-ssl-acceptance-android – user2340612

5

Trước hết bạn cần phải tạo đối tượng SchemeRegistry và đăng ký Đề án mới sử dụng SSLSocketFactory:

SchemeRegistry schemeRegistry = new SchemeRegistry(); 
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); 

Sau đó, bạn có thể tạo SingleClientConnManager bạn sử dụng SchemeRegistry đối tượng:

SingleClientConnManager mgr = new SingleClientConnManager(schemeRegistry); 

Và cuối cùng bạn tạo DefaultHttpClient của bạn với SingleClientConnManager:

HttpClient client = new DefaultHttpClient(mgr); 
+0

bạn có muốn xây dựng thêm một chút về các đối tượng đó không? sao tôi nên thực hiện các bước được mô tả trước khi mọi truy cập vào dịch vụ web https? Theo tôi hiểu tôi sẽ nhận được chứng chỉ từ máy chủ và lưu trữ trên thiết bị, tôi có đúng không? –

+0

@EmilAdz Có, bạn nên thực hiện các bước này trước mỗi lần truy cập https. 'SchemeRegistry' chỉ là một container cho tất cả các đối tượng' Scheme' mô tả các tham số kết nối HTTPS, vì vậy bạn có thể sử dụng một cá thể của đối tượng 'SchemeRegisty' cho tất cả các cuộc gọi của bạn. Nhưng bạn sẽ cần có 'SingleClientConnManager' mới cho mỗi cuộc gọi, bởi vì nó chỉ có thể duy trì một kết nối tại một thời điểm. Tôi nghĩ rằng việc lưu trữ chứng chỉ SSL được cung cấp bởi chính Android, vì vậy bạn không cần phải lo lắng về nó. – nemezis

Các vấn đề liên quan