android httpClient 支持HTTPS的访问方式
16lz
2021-01-23
项目中Android https请求地址遇到了这个异常(无终端认证):
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
是SSL协议中没有终端认证。
没有遇到过的问题,于是无奈的去找度娘。。。。。。。
看了不少大神的博客后得到的解决方案如下:
/***Post请求连接Https服务*@paramserverURL请求地址*@paramjsonStr请求报文*@return*@throwsException*/publicstaticsynchronizedStringdoHttpsPost(StringserverURL,StringjsonStr)throwsException{//参数HttpParamshttpParameters=newBasicHttpParams();//设置连接超时HttpConnectionParams.setConnectionTimeout(httpParameters,3000);//设置socket超时HttpConnectionParams.setSoTimeout(httpParameters,3000);//获取HttpClient对象(认证)HttpClienthc=initHttpClient(httpParameters);HttpPostpost=newHttpPost(serverURL);//发送数据类型post.addHeader("Content-Type","application/json;charset=utf-8");//接受数据类型post.addHeader("Accept","application/json");//请求报文StringEntityentity=newStringEntity(jsonStr,"UTF-8");post.setEntity(entity);post.setParams(httpParameters);HttpResponseresponse=null;try{response=hc.execute(post);}catch(UnknownHostExceptione){thrownewException("Unabletoaccess"+e.getLocalizedMessage());}catch(SocketExceptione){e.printStackTrace();}intsCode=response.getStatusLine().getStatusCode();if(sCode==HttpStatus.SC_OK){returnEntityUtils.toString(response.getEntity());}elsethrownewException("StatusCodeis"+sCode);}privatestaticHttpClientclient=null;/***初始化HttpClient对象*@paramparams*@return*/publicstaticsynchronizedHttpClientinitHttpClient(HttpParamsparams){if(client==null){try{KeyStoretrustStore=KeyStore.getInstance(KeyStore.getDefaultType());trustStore.load(null,null);SSLSocketFactorysf=newSSLSocketFactoryImp(trustStore);//允许所有主机的验证sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);HttpProtocolParams.setVersion(params,HttpVersion.HTTP_1_1);HttpProtocolParams.setContentCharset(params,HTTP.UTF_8);//设置http和https支持SchemeRegistryregistry=newSchemeRegistry();registry.register(newScheme("http",PlainSocketFactory.getSocketFactory(),80));registry.register(newScheme("https",sf,443));ClientConnectionManagerccm=newThreadSafeClientConnManager(params,registry);returnnewDefaultHttpClient(ccm,params);}catch(Exceptione){e.printStackTrace();returnnewDefaultHttpClient(params);}}returnclient;}publicstaticclassSSLSocketFactoryImpextendsSSLSocketFactory{finalSSLContextsslContext=SSLContext.getInstance("TLS");publicSSLSocketFactoryImp(KeyStoretruststore)throwsNoSuchAlgorithmException,KeyManagementException,KeyStoreException,UnrecoverableKeyException{super(truststore);TrustManagertm=newX509TrustManager(){publicjava.security.cert.X509Certificate[]getAcceptedIssuers(){returnnull;}@OverridepublicvoidcheckClientTrusted(java.security.cert.X509Certificate[]chain,StringauthType)throwsjava.security.cert.CertificateException{}@OverridepublicvoidcheckServerTrusted(java.security.cert.X509Certificate[]chain,StringauthType)throwsjava.security.cert.CertificateException{}};sslContext.init(null,newTrustManager[]{tm},null);}@OverridepublicSocketcreateSocket(Socketsocket,Stringhost,intport,booleanautoClose)throwsIOException,UnknownHostException{returnsslContext.getSocketFactory().createSocket(socket,host,port,autoClose);}@OverridepublicSocketcreateSocket()throwsIOException{returnsslContext.getSocketFactory().createSocket();}}run下,小手发抖的点到测试按钮,深吸口气,咦?没反应。。。马蛋的,工作线程忘记start(),唉,再次run下,终于的有点反应了,神奇的竟然没有报之前的 javax.net.ssl.SSLPeerUnverifiedException: No peer certificate 的异常了。服务端的数据正常返回了。,狂喜中…
分析问题:
HTTPS:超文本安全传输协议,和HTTP相比,多了一个SSL/TSL的认证过程,端口为443。
1.peer终端发送一个request,https服务端把支持的加密算法等以证书的形式返回一个身份信息(包含ca颁发机构和加密公钥等)。
2.获取证书之后,验证证书合法性。
3.随机产生一个密钥,并以证书当中的公钥加密。
4.request https服务端,把用公钥加密过的密钥传送给https服务端。
5.https服务端用自己的密钥解密,获取随机值。
6.之后双方传送数据都用此密钥加密后通信。
HTTPS流程清楚后,问题也就明显了,验证证书时,无法验证。
上面提供的解决方案就是添加默认信任全部证书。以此来通过接下来的通信。
但是,这样问题是解决了。但是觉得还是不带靠谱(信任全部证书有点危险)。继续噼噼啪啪的网上搜索一番。又找到了一种解决方案,其过程大致这样的:
1.浏览器访问https地址,保存提示的证书到本地,放到android项目中的assets目录。
2.导入证书,代码如下。
3.把证书添加为信任。
publicstaticStringrequestHTTPSPage(Contextcontext,StringmUrl){InputStreamins=null;Stringresult="";try{ins=context.getAssets().open("my.key");//下载的证书放到项目中的assets目录中CertificateFactorycerFactory=CertificateFactory.getInstance("X.509");Certificatecer=cerFactory.generateCertificate(ins);KeyStorekeyStore=KeyStore.getInstance("PKCS12","BC");keyStore.load(null,null);keyStore.setCertificateEntry("trust",cer);SSLSocketFactorysocketFactory=newSSLSocketFactory(keyStore);Schemesch=newScheme("https",socketFactory,443);HttpClientmHttpClient=newDefaultHttpClient();mHttpClient.getConnectionManager().getSchemeRegistry().register(sch);BufferedReaderreader=null;try{HttpGetrequest=newHttpGet();request.setURI(newURI(mUrl));HttpResponseresponse=mHttpClient.execute(request);if(response.getStatusLine().getStatusCode()!=200){request.abort();returnresult;}reader=newBufferedReader(newInputStreamReader(response.getEntity().getContent()));StringBufferbuffer=newStringBuffer();Stringline=null;while((line=reader.readLine())!=null){buffer.append(line);}result=buffer.toString();}catch(Exceptione){e.printStackTrace();}finally{if(reader!=null){reader.close();}}}catch(Exceptione){e.printStackTrace();}finally{try{if(ins!=null)ins.close();}catch(IOExceptione){e.printStackTrace();}}returnresult;}
更多相关文章
- Android与服务端数据交互 Apache Tomcat + MySQL
- Android静态安全检测 -> 证书弱校验
- android使用JSON进行网络数据交换(服务端、客户端)的实现
- Google Map API V2密钥申请
- Android 7.0 之后抓包 unknown 和证书无效的解决方案(无需改代码)
- Android WebView与服务端交互Demo
- 【android】基于Android的搜索客户端应用团队项目(服务端)
- Android 客户端与服务端交互之登陆示例(Android+servlet+JavaBean
- android 向服务端发送请求编码问题