首先,自己当时做这个任务的时候,借鉴了一位博主的文章,写这篇文章算是记录自己的工作历程吧,毕竟是个新人的开端。
http://www.blogjava.net/icewee/archive/2012/06/04/379947.html
这样就配置好了单向和双向认证,可以启动web项目,直接通过浏览器进行认证了https://localhost:8443/走起
下面上httpclient的代码
先来一个测试的servlet
package com.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.security.cert.X509Certificate;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class GenXmlServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//输出对应的证书
X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
if (certs != null) {
int count = certs.length;
System.out.println("共检测到[" + count + "]个客户端证书");
for (int i = 0; i < count; i++) {
System.out.println("客户端证书 [" + (++i) + "]: ");
System.out.println("校验结果:" + verifyCertificate(certs[--i]));
System.out.println("证书详细:\r" + certs[i].toString());
}
} else {
if ("https".equalsIgnoreCase(request.getScheme())) {
System.out.println("这是一个HTTPS请求,但是没有可用的客户端证书");
} else {
System.out.println("这不是一个HTTPS请求,因此无法获得客户端证书列表 ");
}
}
String name=request.getParameter("name");
String method=request.getMethod();
System.out.println(method);
//get提交进行编码
if(method.equals("GET")){
name=new String(name.getBytes("ISO-8859-1"),"UTF-8");
}
System.out.println("---------------");
System.out.println(name+"我到了");
out.write(name+"我回来了");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
private boolean verifyCertificate(X509Certificate certificate) {
boolean valid = true;
try {
certificate.checkValidity();
} catch (Exception e) {
e.printStackTrace();
valid = false;
}
return valid;
}
}
接下来就是单向和双向的get和post请求了,
单向get请求
package zhufei.danxiang;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLContext;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
public class DXsg {
private static final String SERVER = "https://localhost:8443/WebTset/GenXmlServlet";
public final static void main(String[] args) throws Exception {
// Trust 服务端证书
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(new File("e:\\https\\tomcat.keystore"), "password".toCharArray(),
new TrustSelfSignedStrategy())
.build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
try {
//设置参数
String param="name="+URLEncoder.encode("张三", "UTF-8");
//System.out.println(param);
//建立get请求
HttpGet httpget = new HttpGet(SERVER+"?"+param);
System.out.println("executing request " + httpget.getRequestLine());
//提交请求并获取返回结果
CloseableHttpResponse response = httpclient.execute(httpget);
System.out.println("-----");
try {
//获得返回实体
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
//读取返回内容
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
String text;
while ((text = bufferedReader.readLine()) != null) {
System.out.println(text);
}
bufferedReader.close();
}
EntityUtils.consume(entity);
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
}
package zhufei.danxiang;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.SSLContext;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
public class DXsp {
private static final String SERVER = "https://localhost:8443/WebTset/GenXmlServlet";
public final static void main(String[] args) throws Exception {
// Trust 服务端证书
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(new File("e:\\https\\tomcat.keystore"), "password".toCharArray(),
new TrustSelfSignedStrategy())
.build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
try {
//建立post请求
HttpPost httppost = new HttpPost(SERVER);
//请求参数
List<NameValuePair> formparams=new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("name", "张三"));
UrlEncodedFormEntity urlentity=new UrlEncodedFormEntity(formparams, Consts.UTF_8);
httppost.setEntity(urlentity);
System.out.println("executing request " + httppost.getRequestLine());
//提交请求并获取返回结果
CloseableHttpResponse response = httpclient.execute(httppost);
System.out.println("-----");
try {
//获得返回实体
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
//读取返回内容
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
String text;
while ((text = bufferedReader.readLine()) != null) {
System.out.println(text);
}
bufferedReader.close();
}
EntityUtils.consume(entity);
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
}
双向认证get请求
package zhufei.shxiang;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.security.KeyStore;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class SXsg {
private static final String KEY_STORE_TYPE_JKS = "jks";
private static final String KEY_STORE_TYPE_P12 = "PKCS12";
private static final String SCHEME_HTTPS = "https";
private static final int HTTPS_PORT = 8443;
private static final String HTTPS_URL = "https://localhost:8443/WebTset/GenXmlServlet";
//客户端证书库
private static final String KEY_STORE_CLIENT_PATH = "E:/https/my.p12";
//客户端信任证书库(由服务端证书生成的证书库)
private static final String KEY_STORE_TRUST_PATH = "E:/https/my.truststore";
private static final String KEY_STORE_PASSWORD = "password";
private static final String KEY_STORE_TRUST_PASSWORD = "password";
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ssl();
}
private static void ssl() throws Exception {
//创建一个HttpClient对象
HttpClient httpClient = new DefaultHttpClient();
try {
//获取指定类型的keystore,储存密钥和证书
KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_JKS);
//通过指定路径创建InputStream
InputStream ksIn = new FileInputStream(KEY_STORE_CLIENT_PATH);
InputStream tsIn = new FileInputStream(new File(KEY_STORE_TRUST_PATH));
try {
//从给定输出流中加载keysotre对象
keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray());
trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray());
} finally {
//关闭流
try { ksIn.close(); } catch (Exception ignore) {}
try { tsIn.close(); } catch (Exception ignore) {}
}
//通过证书和密码,获取socketfactory套接字工厂
SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, KEY_STORE_PASSWORD, trustStore);
//创建协Scheme对象,参数http/https(协议模式),默认端口,套接字工厂
Scheme sch = new Scheme(SCHEME_HTTPS, HTTPS_PORT, socketFactory);
//在连接管理器中注册中信息
httpClient.getConnectionManager().getSchemeRegistry().register(sch);
//设置参数
//????编码方式有问题
String param="name="+URLEncoder.encode("张三", "UTF-8");
//创建httppost请求
HttpGet httpget = new HttpGet(HTTPS_URL+"?"+param);
System.out.println("executing request" + httpget.getRequestLine());
//执行post请求,并且返回传递信息的HTTPResponse对象
HttpResponse response = httpClient.execute(httpget);
//获取响应实体
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine().getStatusCode());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
String text;
while ((text = bufferedReader.readLine()) != null) {
System.out.println(text);
}
bufferedReader.close();
}
EntityUtils.consume(entity);
} finally {
//使用连接管理器关闭httpclient
httpClient.getConnectionManager().shutdown();
}
}
}
双向认证post请求
package zhufei.shxiang;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
public class SXsp {
private static final String KEY_STORE_TYPE_JKS = "jks";
private static final String KEY_STORE_TYPE_P12 = "PKCS12";
private static final String SCHEME_HTTPS = "https";
private static final int HTTPS_PORT = 8443;
private static final String HTTPS_URL = "https://localhost:8443/WebTset/GenXmlServlet";
//客户端证书库
private static final String KEY_STORE_CLIENT_PATH = "E:/https/my.p12";
//客户端信任证书库(由服务端证书生成的证书库)
private static final String KEY_STORE_TRUST_PATH = "E:/https/my.truststore";
private static final String KEY_STORE_PASSWORD = "password";
private static final String KEY_STORE_TRUST_PASSWORD = "password";
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ssl();
}
private static void ssl() throws Exception {
//创建一个HttpClient对象
HttpClient httpClient = new DefaultHttpClient();
try {
//获取指定类型的keystore,储存密钥和证书
KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_JKS);
//通过指定路径创建InputStream
InputStream ksIn = new FileInputStream(KEY_STORE_CLIENT_PATH);
InputStream tsIn = new FileInputStream(new File(KEY_STORE_TRUST_PATH));
try {
//从给定输出流中加载keysotre对象
keyStore.load(ksIn, KEY_STORE_PASSWORD.toCharArray());
trustStore.load(tsIn, KEY_STORE_TRUST_PASSWORD.toCharArray());
} finally {
//关闭流
try { ksIn.close(); } catch (Exception ignore) {}
try { tsIn.close(); } catch (Exception ignore) {}
}
//通过证书和密码,获取socketfactory套接字工厂
SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, KEY_STORE_PASSWORD, trustStore);
//创建协Scheme对象,参数http/https(协议模式),默认端口,套接字工厂
Scheme sch = new Scheme(SCHEME_HTTPS, HTTPS_PORT, socketFactory);
//在连接管理器中注册中信息
httpClient.getConnectionManager().getSchemeRegistry().register(sch);
//创建httppost请求
HttpPost httppost = new HttpPost(HTTPS_URL);
//构建post请求的表单参数
List<NameValuePair> formparams=new ArrayList<NameValuePair>();
formparams.add(new BasicNameValuePair("name", "张三"));
formparams.add(new BasicNameValuePair("xml", "<xml><name>烦烦烦</name></xml>"));
//设置编码方式
UrlEncodedFormEntity urlentity=new UrlEncodedFormEntity(formparams, Consts.UTF_8);
httppost.setEntity(urlentity);
System.out.println("executing request" + httppost.getRequestLine());
//执行post请求,并且返回传递信息的HTTPResponse对象
HttpResponse response = httpClient.execute(httppost);
//获取响应实体
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine().getStatusCode());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
String text;
while ((text = bufferedReader.readLine()) != null) {
System.out.println(text);
}
bufferedReader.close();
}
EntityUtils.consume(entity);
} finally {
//使用连接管理器关闭httpclient
httpClient.getConnectionManager().shutdown();
}
}
}
做下总结吧,完成这个工作的时候对https的一些安全认证还不是了解的很清楚,只能说是勉强完成了交代的任务。然后呢,使用keytool生成证书的时候,在httpclient双向验证的时候,要多导出一个,在上面代码和excel表格中有说明,顺便导出服务器证书库的时候,注意姓氏的命名,本机测试localhost,实际应该是用访问域名,还没做到那一步,第一次自己弄的时候,很老实的写上了自己姓名的全拼,结果你懂的。然后配置tomcat和web.xml就没什么问题了,按部就班,不懂的直接百度。
对于httpclient,首先要去下载jar包,然后单向认证很简单,就那样,双向验证略复杂,还有就是post提交有自己的设置参数方法,以及编码方法,get提交我没有找到什么好办法,直接在url后面附加参数,怎么做你懂的,然后问题就来了,编码方法有问题,查了半天才解决,写参数的时候URLEncoder调用方法编码一次,在servlet中接受的时候判断提交方法,get提交就对获取的参数解码再编码一次,就OK了。
附带一些其他的参考博文
http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2112804.html
http://blog.csdn.net/shimiso/article/details/7047447