Android 上的 HTTPS 身份验证
HTTPS auth on Android
我有一些用于 Android 的 HTTP 身份验证代码。但它不适用于 https 身份验证。如何在 https 授权下重构代码?
HTTP 认证代码如下:
HttpUriRequest request = new HttpGet(HOST);
String credentials = login + ":" + mPassword;
authString = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("auth", authString);
editor.apply();
request.addHeader("Authorization", authString);
HttpClient httpClient = new DefaultHttpClient();
int result = 0;
try {
HttpResponse response = httpClient.execute(request);
result = response.getStatusLine().getStatusCode();
System.out.println(response.getStatusLine());
} catch (Exception e) {
result = -1;
}
return result;
The default behaviour of HttpClient is suitable for most uses, however
there are some aspects which you may want to configure. The most
common requirements for customizing SSL are:
- Ability to accept self-signed or untrusted SSL certificates. This is highlighted by an SSLException with the message Unrecognized SSL
handshake (or similar) being thrown when a connection attempt is made.
- You want to use a third party SSL library instead of Sun's default implementation.
您可能需要自定义协议的实现:
Protocol myhttps = new Protocol("https", new MySSLSocketFactory(), 443);
Protocol.registerProtocol("https",
new Protocol("https", new MySSLSocketFactory(), 443));
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.whatever.com/");
try {
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine());
} finally {
httpget.releaseConnection();
}
MySSLSocketFactory
是实现了 org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory
接口的自定义套接字工厂
你可以参考这个 link:MySSLSocketFactory.java
我解决了它,使用自定义 ssl 套接字工厂并使用参数创建 HTTP 客户端。
CustomSSLSocketFactory:
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
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.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.conn.ssl.SSLSocketFactory;
public class CustomSSLSocketFactory extends SSLSocketFactory{
SSLContext sslContext = SSLContext.getInstance("TLS");
/**
* Generate Certificate for ssl connection
* @param truststore
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
* @throws KeyStoreException
* @throws UnrecoverableKeyException
*/
public CustomSSLSocketFactory(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager(){
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
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();
}
}
用于创建 HTTP 客户端的结束实用程序:
import java.security.KeyStore;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
public class HTTPUtils {
/**
* HttpClient
* @param isHTTPS
* @return
*/
public static HttpClient getNewHttpClient(boolean isHTTPS) {
try {
if(!isHTTPS){
return getNewHttpClient();
}
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new CustomSSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return null;
}
}
/**
* HttpClient for http request
* @return
*/
private static HttpClient getNewHttpClient(){
HttpParams params = new BasicHttpParams();
return new DefaultHttpClient(params);
}
}
示例:
String credentials = login + ":" + mPassword;
authString = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
HttpClient httpclient = HTTPUtils.getNewHttpClient(HOST.startsWith(HTTPS_STRING));
URI newURI = URI.create(HOST);
HttpGet httpGet = new HttpGet(newURI);
httpGet.setHeader("Authorization", authString);
try {
HttpResponse response = httpclient.execute(httpGet);
int code = response.getStatusLine().getStatusCode();
return code;
...
我有一些用于 Android 的 HTTP 身份验证代码。但它不适用于 https 身份验证。如何在 https 授权下重构代码?
HTTP 认证代码如下:
HttpUriRequest request = new HttpGet(HOST);
String credentials = login + ":" + mPassword;
authString = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("auth", authString);
editor.apply();
request.addHeader("Authorization", authString);
HttpClient httpClient = new DefaultHttpClient();
int result = 0;
try {
HttpResponse response = httpClient.execute(request);
result = response.getStatusLine().getStatusCode();
System.out.println(response.getStatusLine());
} catch (Exception e) {
result = -1;
}
return result;
The default behaviour of HttpClient is suitable for most uses, however there are some aspects which you may want to configure. The most common requirements for customizing SSL are:
- Ability to accept self-signed or untrusted SSL certificates. This is highlighted by an SSLException with the message Unrecognized SSL handshake (or similar) being thrown when a connection attempt is made.
- You want to use a third party SSL library instead of Sun's default implementation.
您可能需要自定义协议的实现:
Protocol myhttps = new Protocol("https", new MySSLSocketFactory(), 443);
Protocol.registerProtocol("https",
new Protocol("https", new MySSLSocketFactory(), 443));
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.whatever.com/");
try {
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine());
} finally {
httpget.releaseConnection();
}
MySSLSocketFactory
是实现了 org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory
接口的自定义套接字工厂
你可以参考这个 link:MySSLSocketFactory.java
我解决了它,使用自定义 ssl 套接字工厂并使用参数创建 HTTP 客户端。
CustomSSLSocketFactory:
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
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.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.conn.ssl.SSLSocketFactory;
public class CustomSSLSocketFactory extends SSLSocketFactory{
SSLContext sslContext = SSLContext.getInstance("TLS");
/**
* Generate Certificate for ssl connection
* @param truststore
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
* @throws KeyStoreException
* @throws UnrecoverableKeyException
*/
public CustomSSLSocketFactory(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager(){
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
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();
}
}
用于创建 HTTP 客户端的结束实用程序:
import java.security.KeyStore;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
public class HTTPUtils {
/**
* HttpClient
* @param isHTTPS
* @return
*/
public static HttpClient getNewHttpClient(boolean isHTTPS) {
try {
if(!isHTTPS){
return getNewHttpClient();
}
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new CustomSSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return null;
}
}
/**
* HttpClient for http request
* @return
*/
private static HttpClient getNewHttpClient(){
HttpParams params = new BasicHttpParams();
return new DefaultHttpClient(params);
}
}
示例:
String credentials = login + ":" + mPassword;
authString = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
HttpClient httpclient = HTTPUtils.getNewHttpClient(HOST.startsWith(HTTPS_STRING));
URI newURI = URI.create(HOST);
HttpGet httpGet = new HttpGet(newURI);
httpGet.setHeader("Authorization", authString);
try {
HttpResponse response = httpclient.execute(httpGet);
int code = response.getStatusLine().getStatusCode();
return code;
...