单向验证:
第一步: 生成key:
keytool -genkey -alias mykey -keyalg RSA -keystore d:/key/testkey
keytool -export -file d:/key/testkey.crt -alias mykey -keystore d:/key/testkey
由于是本地测试,请修改本地host文件C:WindowsSystem32driversetchost
# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost
127.0.0.1 www.xiaochangwei.com
这样就可以通过域名访问了
第二步:tomcat配置
<Connector port="8448" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="D:key estKey" keystorePass="123456"/>
这里默认是注释掉的 请打开,根据需要可以修改默认的端口,默认端口为8443
在这里需要注意的是,在linux等非windows环境下,会提示 找不到key 或者秘钥过若等提示,在找不到秘钥时tomcat无法正常启动,秘钥过若页面不能正常访问
需解决两点,
①把上面的key加一个后缀以便非windows环境识别
②增加秘钥的复杂度
完整配置如下:
<Connector port="443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile="/opt/apache-tomcat-7.0.64/testkey.keystone" keystorePass="123456" ciphers="TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA"/>
第三步:发布项目
可以看见项目已经发布成功,且端口也可用,下面测试下端口情况
可以看出,都能正常访问,证明已经部署成功。
参考资料:http://lixor.iteye.com/blog/1532655
双向验证
为服务器生成证书 keytool -genkey -v -alias server -keyalg RSA -keystore d:key2server.keystore -validity 36500 为客户端生成证书 keytool -genkey -v -alias client -keyalg RSA -storetype PKCS12 -keystore d:key2client.key.p12 导入客户端证书 让服务器信任客户端证书 1.先把客户端证书到处为cer文件格式 keytool -export -alias client -keystore d:key2client.key.p12 -storetype PKCS12 -storepass 123456 -rfc -file d:key2client.key.cer 2.将客户端cer导入到服务器证书库 keytool -import -v -file d:key2client.key.cer -keystore d:key2server.keystore 3.查看安装结果 keytool -list -keystore d:key2server.keystore 让客户端信任服务器证书 1.把服务器证书到处为cer文件 keytool -keystore d:key2server.keystore -export -alias server -file d:key2server.cer 2.在客户端安装服务器证书 选择受信任的根证书颁发机构 配置tomcat <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="true" sslProtocol="TLS" keystoreFile="D:\key2\server.keystore" keystorePass="123456" truststoreFile="D:\key2\server.keystore" truststorePass="123456" />
HTTP接口的调用说白了无非就是根据地址,先建立链接,然后获取返回的信息或者发送请求数据过去,完成业务逻辑后关闭链接。
可以通过原生态的接口调用方式进行http接口的调用,http://www.cnblogs.com/xiaochangwei/p/5045264.html 也可以采用restful进行,
如果系统要调用的http接口众多,请采用restful统一管理,使代码更清晰
先说说接口调用时,怎么绕过https验证,即别人的项目是以https方式发布的,如果是双向验证,则需要证书密码等。
下面是参考别人的内容,地址:http://blog.csdn.net/noodies/article/details/17240805
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.HttpVersion; import org.apache.http.client.HttpClient; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.PlainSocketFactory; 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.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.HTTP; public class HttpsClient { static public HttpClient newHttpsClient() { 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); HttpConnectionParams.setConnectionTimeout(params, 10000); HttpConnectionParams.setSoTimeout(params, 10000); 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(); } } private static 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); } @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(); } } }
受此启发,我们项目中使用的是restful,则直接修改初始化的httpclient就好了
下面代码就是restful风格进行http接口调用方式,请注意jar包的引入 RestTemplate 在spring-web.jar里面的
package com.xxx.rpc.restclient.utils; 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 java.text.SimpleDateFormat; import java.util.Date; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.client.HttpClient; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.PlainSocketFactory; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.util.StringUtils; import org.springframework.web.client.RestTemplate; @SuppressWarnings("deprecation") public class HttpClientUtils { private static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class); private static String HTTP_PROTOCOL = "https://"; public static ResponseEntity<String> Execute(FrontInfo frontInfo) { HttpClient httpClient = null; try { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); SSLSocketFactory sf = new MySSLSocketFactory(trustStore); sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), Integer.valueOf(frontInfo.getPort()))); registry.register(new Scheme("https", sf, Integer.valueOf(frontInfo.getPort()))); ClientConnectionManager ccm = new ThreadSafeClientConnManager(registry); httpClient = new DefaultHttpClient(ccm); } catch (Exception e) { logger.info("httpclient创建错误."); } HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); httpComponentsClientHttpRequestFactory.setConnectTimeout(120*1000); httpComponentsClientHttpRequestFactory.setReadTimeout(120*1000); RestTemplate rt = new RestTemplate(httpComponentsClientHttpRequestFactory); String url = HttpClientUtils.generateUrl(frontInfo); HttpEntity<String> requestEntity = HttpClientUtils.generateHttpEntity(frontInfo); try { System.out.println("httpMethod = " + frontInfo.getHttpMethod()); System.out.println("url = " + url); System.out.println("requestEntity = " + requestEntity); ResponseEntity<String> responseEntity = rt.exchange(url, frontInfo.getHttpMethod(), requestEntity, String.class); logger.debug("responseEntity = [{}].", responseEntity); System.out.println("responseEntity = " + responseEntity); return responseEntity; } catch (Exception e) { System.out.println("info: " + e.getMessage()); logger.debug("error info: = [{}].", e.getMessage()); return generateRespWhenException(e); } }
由于是商业项目的代码,所以仅贴一部分代码,根据这个就可以完全掌握restful相关技术,需要解释下的是:
① frontInfo 是一个共通的参数对象,为保证接口调用方式统一,里面有各接口需要的参数名等,如ip,prot,url,method,username 等等......
② generateUrl 是根据共通参数对象及条件生成具体的url,如 https://www.xiaochangwei.com/http/web/getuser.do?username=xiaogege&age=28
③ generateHttpEntity 是根据具体的业务需要增加一些共通的header信息
④ exchange 就是具体的执行了,返回ResponseEntity<String>,然后根据具体的业务返回,进行解析
⑤ 调用后解析返回信息大致如下,解析其中的body
JSONObject object = JSONObject.parseObject(response.getBody().toString()); JSONObject userJson = JSONObject.parseObject(object.getString("user")); String uuid = userJson.getString("id");
至此restful使用方式介绍完毕