maven依赖
这里引用Apache的httpclient包和springweb的RestTemplate。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
java客户端调用https步骤
两种方式:
第一种自定义证书存储位置,需要在代码中指定
第二种需要把证书导入到jre秘钥库中
#1.调用方导入服务器证书到自定义keystore位置
keytool -import -v -trustcacerts -alias [别名,随便] -file [brightfood.cer] -storepass [123456] -keystore [存储keystore的位置,truststore]
#代码中调用https前添加以下两句
System.setProperty("javax.net.ssl.trustStore","./demo\\files\\cert\\truststore");//自定义的keystore位置
System.setProperty("javax.net.ssl.trustStorePassword", "123456");//keystore密码
#2.调用放导入服务器证书到jre秘钥库
keytool -import -v -trustcacerts -alias【别名】-file [brightfood.cer] -storepass [123456] -keystore [%JAVA_HOME%/jre/lib/security/cacerts]
#代码不用动
示例代码
示例给出了四种方式:
1.RestTemplate使用jre秘钥库,测试方法tryRestTemplate()
2.RestTemplate自定义加载证书,测试方法tryRestTemplateCustom()
3.HttpClient自定义认证,测试方法tryApacheComponentVerify()
4.HttpClient跳过认证,测试方法tryApacheComponentVerifyNoVerify()
package com.demo.http;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateException;
/**
* <p>https请求测试</p>
* @author lch
* @version 1.0
* @date 2022/5/13 10:41
*/
public class HttpRequestTest {
/**
* https访问
* 服务提供方证书,需要添加到jre秘钥库,路径%JAVA_HOME%/jre/lib/security/cacerts
* 1.从浏览器中导出cer格式的证书,或者使用crt格式
* 2.keytool -import -v -trustcacerts -alias【别名】-file brightfood.cer/crt -storepass 123456 -keystore %JAVA_HOME%/jre/lib/security/cacerts
* 如果自定义存储路径,代码中需要设置以下系统属性
* System.setProperty("javax.net.ssl.trustStore","./demo\\files\\cert\\truststore");
* System.setProperty("javax.net.ssl.trustStorePassword", "123456");
* @param args
*/
public static void main(String[] args) {
//System.getProperties().list(System.out);
}
/**
* <p>{@link RestTemplate}方式</p>
*/
@Test
public void tryRestTemplate(){
/**
* 如果设置了jre的秘钥库就不需要下面两句
*/
//System.setProperty("javax.net.ssl.trustStore","./demo\\files\\cert\\truststore");
//System.setProperty("javax.net.ssl.trustStorePassword", "123456");
RestTemplate template=new RestTemplate();
ResponseEntity<String> forEntity = template.getForEntity("https://fssc.brightfood.com", String.class);
String body = forEntity.getBody();
System.out.println(body);
}
/**
* <p>{@link RestTemplate}自定义认证</p>
*/
@Test
public void tryRestTemplateCustom() throws IOException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
final String pwd = "123456";
SSLContext sslContext = SSLContextBuilder
.create()
.loadTrustMaterial(new File("./demo\\files\\cert\\truststore"), pwd.toCharArray(),TrustAllStrategy.INSTANCE)
.build();
HttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
//.setSSLHostnameVerifier()
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(client);
RestTemplate restTemplate = new RestTemplate(requestFactory);
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
ResponseEntity<String> forEntity = restTemplate.getForEntity("https://fssc.brightfood.com", String.class);
String body = forEntity.getBody();
System.out.println(body);
}
/**
* <p>Apache {@link HttpClient}方式</p>
*/
@Test
public void tryApacheComponentVerify(){
String url="https://fssc.brightfood.com";
HttpGet get=new HttpGet(url);
String request = request(get, true);
System.out.println(request);
}
/**
* <p>Apache {@link HttpClient}方式,跳过认证</p>
*/
@Test
public void tryApacheComponentVerifyNoVerify(){
String url="https://fssc.brightfood.com";
HttpGet get=new HttpGet(url);
String request = request(get, false);
System.out.println(request);
}
/**
* <p>发请求</p>
* @param url url
* @param verify 是否ssl认证
* @return http body
*/
private static String request(HttpUriRequest url, boolean verify){
try {
CloseableHttpClient httpsClient = getHttpsClient(verify);
CloseableHttpResponse httpResponse = httpsClient.execute(url);
HttpEntity entity = httpResponse.getEntity();
String res = EntityUtils.toString(entity);
httpResponse.close();
httpsClient.close();;
return res;
} catch (GeneralSecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static CloseableHttpClient getHttpsClient(boolean verify) throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException, IOException, CertificateException {
if (verify){
KeyStore keyStore=KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream inputStream=new FileInputStream(new File(System.getProperty("java.home")+"/lib/security/cacerts"));
//keystore密码,如果采用自己生成的keystore需要换成自己的密码,jre秘钥库默认密码changeit
keyStore.load(inputStream,"changeit".toCharArray());
SSLContext sslContext= SSLContexts.custom()
.loadTrustMaterial(keyStore, TrustAllStrategy.INSTANCE)
.build();
CloseableHttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
//.setSSLHostnameVerifier(new DefaultHostnameVerifier())
.build();
return client;
}else {
SSLContext sslContext= SSLContexts.custom()
.loadTrustMaterial(null, TrustAllStrategy.INSTANCE)
.build();
CloseableHttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build();
return client;
}
}
}
jdk工具生成证书常用命令
#jdk工具生成证书crt的keystore
keytool -genkey -alias [别名] -keyalg RSA [-storetype PKCS12] [-keysize 2048] -keypass [私钥密码] [-validity 365] -keystore [D:\\key\\ssodemo.keystore] -storepass [keystore密码]
#alias:密钥别名
#storetype:可选,指定密钥仓库类型
#keyalg:生证书的算法名称,一般RSA
#keysize:可选,证书长度
#keystore:生成的证书文件的存储路径
#storepass:秘钥库密码
#keypass:表示别名条目的密码(私钥的密码)
#validity:可选,证书的有效期
#查看test.keystore秘钥库的证书条目
keytool -list -keystore test.keystore
#导出证书
keytool -export -alias [别名] -file [xx.crt] -keystore [xx.keystore] -storepass [123456]
#从keystore导入证书 到crt文件中
cd d:/jre8/bin
keytool -import -file [xx.crt] -keystore [d:/crtTrust.trustStore]-alias [别名] -storepass [password]
#jre秘钥库导入https证书,java_home是环境变量配置的
keytool -import -v -trustcacerts -alias 【别名】-file wosignssl.cer -storepass changeit -keystore %JAVA_HOME%/jre/lib/security/cacerts
#从jre秘钥库删除别名为brightfood的条目
keytool -delete -alias brightfood -keystore %JAVA_HOME%/jre/lib/security/cacerts -storepass changeit
springboot配置https访问
不建议直接配置,如果外层有nginx最好配在nginx上
#yaml中加入修改内容key-store是秘钥库位置,key-alias是证书对应的别名,key-store-password是秘钥库密码
#这种方式只能通过https访问
server:
ssl:
key-store: classpath:\cert\test.keystore
key-alias: test
key-store-password: 123456
port: 8080
?若要配置同时启用http、https访问,还需添加tomcat的connector
//注册到spring容器中
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addAdditionalTomcatConnectors(createHTTPConnector());
return tomcat;
}
private Connector createHTTPConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
//同时启用http(80)、https(443)两个端口
connector.setScheme("http");
connector.setSecure(false);
connector.setPort(80);
connector.setRedirectPort(443);
return connector;
}
|