有些响应https请求的接口,需要在客户端添加证书的情况,其目的是加密在网络之间传输的请求报文,保证信息安全;
证书的加密方式多种多样,本案例以JKS加密的证书为例:
1.获取证书私钥PrivateKey
private static PrivateKey getPrivateKey(String priKeyFile, String storePassword) throws Exception {
char[] storePwdArr;
int i;
BufferedInputStream bis = null;
try {
KeyStore ks = KeyStore.getInstance("JKS");
//加载证书
FileInputStream fis = new FileInputStream(priKeyFile);
bis = new BufferedInputStream(fis);
//证书中的加密key
String storeAlias = "signKey";
storePwdArr = new char[storePassword.length()];// store password
for (i = 0; i < storePassword.length(); i++) {
storePwdArr[i] = storePassword.charAt(i);
}
ks.load(bis, storePwdArr);
PrivateKey priv = (PrivateKey) ks.getKey(storeAlias, storePwdArr);
return priv;
} catch (KeyStoreException e) {
e.printStackTrace();
throw new Exception("1");
} catch (FileNotFoundException e) {
e.printStackTrace();
throw new Exception("2", e);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new Exception("3", e);
} catch (CertificateException e) {
e.printStackTrace();
throw new Exception("4", e);
} catch (IOException e) {
e.printStackTrace();
throw new Exception("5", e);
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
throw new Exception("6", e);
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
SSL实现(HTTP请求):
1.请求构建:
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* HTTP请求
*
*/
public class HttpRequestUtil
{
final static String PROTOCOL_NAME = "https";
private static final Logger logger = LoggerFactory.getLogger(HttpRequestUtil.class);
public static String sendJsonWithHttp(String surl, String json) throws Exception
{
URL url = new URL(surl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
conn.setRequestMethod("POST");// 提交模式
conn.setRequestProperty("Content-Length", json.getBytes().length + "");
conn.setConnectTimeout(100000);// 连接超时单位毫秒 //
conn.setReadTimeout(200000);// 读取超时 单位毫秒
conn.setDoOutput(true);// 是否输入参数
conn.setDoInput(true);
conn.setUseCaches(false);
conn.connect();
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
out.write(json.getBytes());
out.flush();
out.close();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuffer sb = new StringBuffer();
String line;
while ((line = reader.readLine()) != null)
{
sb.append(line);
}
reader.close();
conn.disconnect();
return sb.toString();
}
public static String https(String surl, String json)
{
HttpClient client =getHttpClient();
client.getParams().setContentCharset("UTF-8");
PostMethod post = new PostMethod(surl);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Protocol httpProtocol;
try {
//声明协议类型
httpProtocol = new Protocol(PROTOCOL_NAME, new SSLProtocolSocketFactory(false), 443);
Protocol.registerProtocol(PROTOCOL_NAME, httpProtocol);
//声明报文格式
post.setRequestHeader("Content-Type", "application/json;charset=utf-8");
RequestEntity requestEntity = null;
requestEntity = new ByteArrayRequestEntity(json.getBytes("utf-8"));
post.setRequestEntity(requestEntity);
//执行调用
client.executeMethod(post);
String off = "ON";
InputStream in = null;
in = post.getResponseBodyAsStream();
byte[] buf = new byte[2048];
do
{
int n = in.read(buf);;
if (n > 0)
{
baos.write(buf, 0, n);
}
else if (n <= 0)
{
break;
}
} while (true);
}catch (HttpException e) {
logger.info("http exception when send http.", e);
} catch (IOException e) {
logger.info("io exception when send http.", e);
}
finally {
post.releaseConnection();
httpProtocol=null;
}
return baos.toString();
}
private static HttpClient httpClient=null;
public static HttpClient getHttpClient()
{
if(httpClient==null)
{
HttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams params = httpConnectionManager.getParams();
params.setConnectionTimeout(1000*60);
params.setSoTimeout(20000);
//避免异常的两行diamante
params.setDefaultMaxConnectionsPerHost(1000);
params.setMaxTotalConnections(2000);
httpClient = new HttpClient(httpConnectionManager);
}
return httpClient;
}
}
2.SSLProtocolSocketFactory必不可少
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import javax.net.SocketFactory;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
/**
*
*/
public class SSLProtocolSocketFactory implements ProtocolSocketFactory {
private boolean isChkCert;
public SSLProtocolSocketFactory(boolean chkCert) {
this.isChkCert = chkCert;
}
@Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
if (params == null) {
throw new IllegalArgumentException("Parameters may not be null!");
}
int timeout = params.getConnectionTimeout();
SocketFactory socketFactory = SSLContextFactory.getInstance(this.isChkCert).getSocketFactory();
if (timeout == 0) {
return createSocket(host, port, localAddress, localPort);
}
Socket socket = socketFactory.createSocket();
SocketAddress localAddress_ = new InetSocketAddress(localAddress, localPort);
SocketAddress remoteAddress = new InetSocketAddress(host, port);
socket.bind(localAddress_);
socket.connect(remoteAddress, timeout);
return socket;
}
@Override
public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException, UnknownHostException {
return SSLContextFactory.getInstance(this.isChkCert).getSocketFactory().createSocket(host, port, localAddress, localPort);
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return SSLContextFactory.getInstance(this.isChkCert).getSocketFactory().createSocket(host, port);
}
}
3.SSLContextFactory
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
*/
public class SSLContextFactory {
private static final Logger logger = LoggerFactory.getLogger(SSLContextFactory.class);
private static SSLContext ctx;
private final static String PROTOCAL_NAME = "SSL";
public static SSLContext getInstance(boolean chkCert) {
if (ctx == null) {
try {
ctx = SSLContext.getInstance(PROTOCAL_NAME);
if (chkCert) {
logger.error("请实现证书信任连接!");
} else {
ctx.init(null, new TrustManager[] {new TrustAnyTrustManager()}, new SecureRandom());
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return ctx;
}
return ctx;
}
}