我是 REST 服务的新用户。我需要使用 Jersey 生成的 RESTful API 服务。问题的出现是因为该服务托管在远程主机上,并且需要使用证书进行 https 访问。
我从该组织获得了证书,并且可以使用我的任何浏览器(在其上设置了证书)访问该 REST API 服务。
我在这里阅读了很多帖子,并且遵循了有关该主题的答案: 在 Java 中将 HTTPS 与 REST 结合使用
现在我已在 Java 密钥库中设置了证书。但我不知道如何在我的 Java 程序上使用它,因此它完全使用我进行 https 连接所需的证书。
这是我用于本地测试的简单连接代码。
package rest.test.first;
import java.net.URI;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
public class TestClient{
public static void main(String[]args){
ClientConfig config= new DefaultClientConfig();
Client client=Client.create(config);
WebResource service=client.resource(getBaseURI());
//Fluentinterfaces
System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_PLAIN).get(ClientResponse.class).toString());
//Getplaintext
System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_PLAIN).get(String.class));
//GetXML
System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_XML).get(String.class));
//TheHTML
System.out.println(service.path("rest").path("hello").accept(MediaType.TEXT_HTML).get(String.class));
}
private static URI getBaseURI(){
return UriBuilder.fromUri("http://localhost:8080/rest.test").build();
}
}
我读过有关使用系统设置属性通过以下代码指定密钥库的路径:
System.setProperty("javax.net.ssl.keyStore", "/path/to/keystore.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "password");
连接远程服务器时仍然出现 401 错误。
但是我不知道如何使用密钥库上的证书进行 SSL 连接。 我也一直在阅读有关使用 sslSocketFactory 来实现此目的的信息,但我无法按照这篇文章中的说明使其工作:如何在特定连接上使用不同的证书?
我已经设法使用此代码从密钥库检索我的证书..现在我只需要知道如何连接使用它:
package rest.test.first;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
public class keystore {
public static void main(String[] args) throws Exception {
String keystoreFilename = "/usr/lib/jvm/jdk1.6.0_32/jre/lib/security/cacerts";
char[] password = "changeit".toCharArray();
String alias = "remote_https_server";
FileInputStream fIn = new FileInputStream(keystoreFilename);
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(fIn, password);
Certificate cert = keystore.getCertificate(alias);
System.out.println(cert);
}
}
好吧,这是我写的最后一个脚本。我可以连接到 https 站点,但仍然无法连接到需要发送证书进行身份验证的 https 站点。
package rest.test.first;
import java.io.*;
import java.net.*;
import java.security.*;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
public class urlConnection{
public static void main(String args[]) throws Exception {
System.setProperty("javax.net.ssl.trustStore", "/usr/lib/jvm/jdk1.6.0_32/jre/lib/security/cacerts");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
//TrustStore..
char[] passphrase = "changeit".toCharArray(); //password
KeyStore keystore = KeyStore.getInstance("JKS");
//KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(new FileInputStream("/usr/lib/jvm/jdk1.6.0_32/jre/lib/security/cacerts"), passphrase); //path
//TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); //instance
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keystore);
SSLContext context = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = tmf.getTrustManagers();
context.init(null, trustManagers, null);
SSLSocketFactory sf = context.getSocketFactory();
URL url = new URL("https://www.google.es");
HttpsURLConnection httpsCon = (HttpsURLConnection) url.openConnection();
httpsCon.setSSLSocketFactory(sf);
httpsCon.setRequestMethod("GET");
/*InputStream inStrm = httpsCon.getInputStream();
System.out.println("\nContent at " + url);
int ch;
while (((ch = inStrm.read()) != -1)){
System.out.print((char) ch);
inStrm.close();
}*/
System.out.println("Response Message is " + httpsCon.getResponseMessage());
}
}
假设您正在服务器上部署此代码,并且您已正确完成其他所有操作(例如正确生成密钥库核心并将其放置在服务器可以访问的位置,使用与代码相同的 java 版本来生成密钥库)那么我认为你需要做的是添加以下内容
<Connector SSLEnabled="true" clientAuth="false" keystoreFile="pathToKeystore" keystorePass="password" maxThreads="150" port="443" protocol="HTTP/1.1" scheme="https" secure="true" sslProtocol="TLS"/>
在您运行客户端的服务器实例的 server.xml 中,并且
<Connector connectionTimeout="20000" port="80" protocol="HTTP/1.1" redirectPort="8443"/>
IMP:如果您将 Skype 与此代码一起使用,请务必(取消选中)更改默认值,因为它还使用相同的端口(80 和 443)进行其他连接
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import javax.net.ssl.SSLContext;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.SSLSocketFactory;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
public class RestTemplateExampleWithPfx {
private static final String PFX_FILE_PATH = "path/to/your/file.pfx";
private static final String PFX_PASSWORD = "yourPfxPassword";
public static void main(String[] args) throws Exception {
// Configure SSL context with the .pfx file
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyStore keyStore = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream(PFX_FILE_PATH)) {
keyStore.load(fis, PFX_PASSWORD.toCharArray());
}
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, PFX_PASSWORD.toCharArray());
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// Create and configure RestTemplate
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
// Configure HttpClient with SSL settings
org.apache.http.impl.client.CloseableHttpClient httpClient = org.apache.http.impl.client.HttpClients.custom()
.setSSLSocketFactory(new org.apache.http.conn.ssl.NoopHostnameVerifier().createSocketFactory())
.build();
restTemplate.setRequestFactory(new org.springframework.http.client.HttpComponentsClientHttpRequestFactory(httpClient));
// Define the custom media type
String customMediaType = "application/vnd.kafka.json.v2+json";
// Create headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(org.springframework.http.MediaType.valueOf(customMediaType));
headers.setAccept(java.util.Collections.singletonList(org.springframework.http.MediaType.APPLICATION_JSON));
// Create data to send
ArrayList<String> data = new ArrayList<>();
data.add("example1");
data.add("example2");
// Create HttpEntity
HttpEntity<ArrayList<String>> requestEntity = new HttpEntity<>(data, headers);
// Define the URL for the POST request
String url = "https://example.com/api/resource";
// Send the POST request
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
// Process the response
if (response.getStatusCode() == HttpStatus.OK) {
System.out.println("Response: " + response.getBody());
} else {
System.out.println("Failed with HTTP error code: " + response.getStatusCodeValue());
}
}
}