Android在使用HttpClient访问https时认证策略
Android中自带Apache的HttpClient包,详见google的API[url]
http://developer.android.com/reference/org/apache/http/package-summary.html
[/url]所以在无需要任何引用的情况下就可以使用HttpClient相关的东西。但是,Android中的HttpClient与http://hc.apache.org/downloads.cgi中的httpclient还是有所区别的,最主要的一个区别就是,Post方法时,Android的包支持自动重定向,而Apache官方的包不支持。
当访问https时,认证方案在客户端可以决定是否验证服务器,而服务器端可以选择是否验证客户端,如果双方都选择验证那么,就是双向验证;如果有一方选择不验证,那就是单向验证。作为客户端的Android单向验证和双向验证如下。
1单向验证,即不验证服务器,在连接过程中首先读取本地客户端证书,然后采用不验证服务端信任证书的方式建立SSLContext,建立主要过程如下:
protected Object doInBackground(Object... params) { // TODO Auto-generated method stub try{ KeyManagerFactory keyManager = KeyManagerFactory.getInstance(KEY_MANAGER); KeyStore keyKeyStore = KeyStore.getInstance(KEY_KEYSTORE); File fk=new File(mKPath); FileInputStream kIs = new FileInputStream(fk); keyKeyStore.load(kIs,KSPWD.toCharArray()); kIs.close(); keyManager.init(keyKeyStore,KSPWD.toCharArray()); GetSecPolicy client=new GetSecPolicy(HOST, SERVER_PORT, keyManager.getKeyManagers()); UserID=client.getUserID(targetPage, null, null, true); toast.setText(UserID); toast.show(); if("1".equals(UserID)){ System.out.println("用户名或密码错误!UserID:"+UserID); toast.setText("用户名或密码错误!"); toast.show(); }else{ System.out.println("用户名和密码认证成功!UserID:"+ UserID); //toast.setText("用户名和密码认证成功!"); //toast.show(); //取出IMEI值,进行终端检查 TelephonyManager tm = (TelephonyManager) SoftCertUserLogin.this.getSystemService(Context.TELEPHONY_SERVICE); String deviceId = tm.getDeviceId();//取出IMEI //进行终端检查 System.out.println(OpenVpnAnimationActivity.USER_TYPE); boolean check = client.secCheck(UserID, OpenVpnAnimationActivity.USER_TYPE, deviceId); System.out.println(OpenVpnAnimationActivity.USER_TYPE); if(check){//验证通过 //获取用户的的用户信息策略 System.out.println("checked!"); String loginPolicy = client.getSecLoginPolicy(UserID); if(loginPolicy == null){ toast.setText("获取用户信息策略失败!"); toast.show(); System.out.println("获取用户信息策略失败!"); }else{//成功获取seclogininfo System.out.println(loginPolicy); Intent intent = new Intent(); // intent.putExtra("loginPolicy", loginPolicy);//传给下一个Activity intent.setClass(SoftCertUserLogin.this, MainpageActivity.class); Bundle mBundle = new Bundle(); mBundle.putString("Seclogin", loginPolicy);//压入数据 intent.putExtras(mBundle); SoftCertUserLogin.this.startActivity(intent); if(version >= 5) { overridePendingTransition(R.anim.zoomin, R.anim.zoomout); //此为自定义的动画效果,下面两个为系统的动画效果 //overridePendingTransition(android.R.anim.fade_in,android.R.anim.fade_out); //overridePendingTransition(android.R.anim.slide_in_left,android.R.anim.slide_out_right); } SoftCertUserLogin.this.finish(); } }else{//验证失败 toast.setText("并没有绑定此手机,请重新登录!"); toast.show(); System.out.println("并没有绑定此手机,请重新登录!"); } } }catch(Exception e){ toast.setText("错误:"+e.getMessage()); toast.show(); } return null; }
其中MySSLSocketFactory实现如下:
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.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.conn.ssl.SSLSocketFactory; 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) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; sslContext.init(null, new TrustManager[] { tm }, null); } public MySSLSocketFactory(KeyManager[] keys,KeyStore truststore ) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; sslContext.init(keys, 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(); } }
2双向认证,即读取服务器端的信任证书
建立httpclient的SSLContext如下:
SSLContext sslContext = SSLContext.getInstance(Constants.SSL.AGREEMENT); KeyManagerFactory keyManager = KeyManagerFactory.getInstance(Constants.SSL.KEY_MANAGER); TrustManagerFactory trustManager = TrustManagerFactory.getInstance(Constants.SSL.TRUST_MANAGER); KeyStore keyKeyStore = KeyStore.getInstance(Constants.SSL.KEY_KEYSTORE); KeyStore trustKeyStore = KeyStore.getInstance(Constants.SSL.TRUST_KEYSTORE); FileInputStream kIs = new FileInputStream(mPath); keyKeyStore.load(kIs,KSPWD.toCharArray()); kIs.close(); FileInputStream tkIS = new FileInputStream(mPath); trustKeyStore.load(tkIS,TKSPWD.toCharArray()); tkIS.close(); keyManager.init(keyKeyStore,KSPWD.toCharArray()); trustManager.init(trustKeyStore); sslContext.init(keyManager.getKeyManagers(), trustManager.getTrustManagers(), null);
在MySSLSocketFactory中添加相应构造函数即可。
[同时需要指明,android只支持bks格式的密库,而且android中自带BouncyCastle的包,不同版本BouncyCastle生成的密库是不兼容的,所以要注意密库版本]
相关推荐
创建一个 HttpClient 实例,这个实例需要调用 Dispose 方法释放资源,这里使用了 using 语句。接着调用 GetAsync,给它传递要调用的方法的地址,向服务器发送 Get 请求。