eclipse中使用Jetty外掛實現https請求與SSL雙向驗證
阿新 • • 發佈:2019-01-08
連結
完整程式原始碼下載,csdn還沒驗證通過
1. 包含https和socket兩種ssl測試程式碼
2. 所有密碼均為123456
環境準備
- eclipse中安裝run-jetty-run外掛 csdn下載資源
- java環境支援,需要使用keytool命令
開始
生成伺服器證書
- keytool -genkey -alias serverkey -keyalg RSA -keystore kserver.keystore
- keytool -export -alias serverkey -keystore kserver.keystore -rfc -file server.crt
- keytool -import -alias serverkey -file server.crt -keystore tclient.keystore
其中:kserver.keystore就是服務使用的keystore,server.crt是證書,tclient.keystore是給客戶端使用的信任keystore
特別說明:這裡我們使用自己的keystore直接匯出證書,僅在自己的內部系統可用,如果希望在公網可用,應生成crs向ca申請證書
生成客戶端證書
JKS方式
- keytool -genkey -alias clientKey -keystore kclient.keystore
- keytool -export -alias clientKey -keystore kclient.keystore -file client.crt
- keytool -import -alias clientKey -file client.crt -keystore tserver.keystore
PKCS12方式
- keytool -genkeypair -alias clientkey -keyalg RSA -storetype PKCS12 -keystore client.p12
- keytool -export -alias clientKey -keystore client.p12 -storetype PKCS12 -rfc -file client.crt
- keytool -import -alias clientKey -file client.crt -keystore tserver.keystore
配置Jetty環境
特別說明:這裡單獨配置了jetty.xml檔案,因為無法確認jetty在做雙向驗證時候的可信證書從哪裡找的,所以通過jetty.xml檔案來指定位置。如果使用單向驗證,那麼可以直接使用jetty的ssl配置即可。
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector">
<Arg>
<New class="org.eclipse.jetty.http.ssl.SslContextFactory">
<Set name="keyStore">D:/workspace/SSLServer/src/ssl/keystore/server/kserver.keystore</Set>
<Set name="keyStorePassword">123456</Set>
<Set name="keyManagerPassword">123456</Set>
<!-- JSK -->
<Set name="trustStore">D:/workspace/SSLServer/src/ssl/keystore/client/tserver.keystore</Set>
<!-- PKCS12 -->
<!--<Set name="trustStore">D:/workspace/SSLServer/src/ssl/keystore/pk12/tserver.keystore</Set>-->
<Set name="trustStorePassword">123456</Set>
<Set name="needClientAuth">true</Set>
</New>
</Arg>
<Set name="port">8443</Set>
<Set name="maxIdleTime">30000</Set>
</New>
</Arg>
</Call>
</Configure>
客戶端請求程式碼
package ssl.https;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.SecureRandom;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
public class SSLSayClient {
private static final String CLIENT_KEY_STORE_PASSWORD = "123456";
private static final String CLIENT_TRUST_KEY_STORE_PASSWORD = "123456";
private SSLSocketFactory ssLSocketFactory;
public static void main(String[] args) throws Exception {
String path = "https://192.168.1.83:8443/SSLServer/say";
SSLSayClient client = new SSLSayClient();
client.init();// 雙向驗證
// client.initOneWay();// 單向驗證
client.doPost(path);
}
static {
// 預設ip地址校驗通過
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
/**
* 雙向驗證
*/
public void init() {
try {
SSLContext ctx = SSLContext.getInstance("SSL");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");// JKS
// KeyStore ks = KeyStore.getInstance("PKCS12");// PKCS12
KeyStore tks = KeyStore.getInstance("JKS");
// JSK
ks.load(new FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/client/kclient.keystore"), CLIENT_KEY_STORE_PASSWORD.toCharArray());
// PKCS12
// ks.load(new
// FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/pk12/client.p12"),
// CLIENT_KEY_STORE_PASSWORD.toCharArray());
tks.load(new FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/server/tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
kmf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());
tmf.init(tks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
ssLSocketFactory = ctx.getSocketFactory();
} catch (Exception e) {
System.out.println(e);
}
}
/**
* 單向驗證
*/
public void initOneWay() {
try {
SSLContext ctx = SSLContext.getInstance("SSL");
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
KeyStore tks = KeyStore.getInstance("JKS");
tks.load(new FileInputStream("D:/workspace/SSLServer/src/ssl/keystore/server/tclient.keystore"), CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
tmf.init(tks);
ctx.init(null, tmf.getTrustManagers(), new SecureRandom());
ssLSocketFactory = ctx.getSocketFactory();
} catch (Exception e) {
System.out.println(e);
}
}
/**
* POST
*/
public void doPost(String path) throws Exception {
if (ssLSocketFactory == null) {
System.out.println("ERROR");
return;
}
// 建立URL物件
URL myURL = new URL(path);
// 建立HttpsURLConnection物件,並設定其SSLSocketFactory物件
HttpsURLConnection httpsConn = (HttpsURLConnection) myURL.openConnection();
httpsConn.setSSLSocketFactory(ssLSocketFactory);
String encoding = "UTF-8";
byte[] data = "Hello Server".getBytes(encoding);
httpsConn.setRequestMethod("POST");
httpsConn.setDoOutput(true);
httpsConn.setRequestProperty("Content-Type", "application/json; charset=" + encoding);
httpsConn.setRequestProperty("Content-Length", String.valueOf(data.length));
OutputStream outStream = httpsConn.getOutputStream();
outStream.write(data);
outStream.flush();
outStream.close();
BufferedReader a = new BufferedReader(new InputStreamReader(httpsConn.getInputStream(), "UTF-8"));
String line = null;
while ((line = a.readLine()) != null) {
System.out.println(line);
}
}
}
服務端程式碼
package ssl.https;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Say extends HttpServlet {
private static final long serialVersionUID = -840442603737824400L;
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Server Get");
String encoding = "UTF-8";
response.setContentType("application/json; charset=" + encoding);
OutputStream outStream = response.getOutputStream();
outStream.write("Hello Client Get".getBytes(encoding));
outStream.flush();
outStream.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Server Post");
BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
String encoding = "UTF-8";
response.setContentType("application/json; charset=" + encoding);
OutputStream outStream = response.getOutputStream();
outStream.write("Hello Client Post".getBytes(encoding));
outStream.flush();
outStream.close();
}
}
驗證
啟動jetty伺服器
提示以下資訊,證明伺服器啟動正常
2016-02-23 10:38:52.628:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/SSLServer,[file:/D:/workspace/SSLServer/WebContent/]}
2016-02-23 10:38:52.710:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8088
2016-02-23 10:38:52.896:INFO:oejus.SslContextFactory:Enabled Protocols [SSLv2Hello, SSLv3, TLSv1] of [SSLv2Hello, SSLv3, TLSv1]
2016-02-23 10:38:52.899:INFO:oejs.AbstractConnector:Started SslSelectChannelConnector@0.0.0.0:8443
執行客戶端ssl雙向請求
如果請求成功,將出現如下資訊:
客戶端提示:
Hello Client Post
服務端提示:
Server Post
Hello Server