springBoot发布https服务及调用
一、服务端发布https服务
1、准备SSL证书
(1)自签名证书:如果你只是用于开发或测试环境,可以生成一个自签名证书。
(2)CA 签名证书:对于生产环境,应该使用由受信任的证书颁发机构 (CA) 签名的证书。
这里采用生成自签名证书,可以使用keytool工具生成自签名证书(jdk工具):
keytool -genkeypair -alias myapp -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650
这将创建一个有效期为 10 年的自签名证书,并将其存储在 keystore.p12
文件中。你需要提供一些信息,如组织名称等。注意记住密码和别名。
如下图:
2、配置springboot启用HTTPS并指定SSL证书的位置和密码
用application.properties
或 application.yml都可以。这样配置可以读取环境变量
把证书放在resource的ssl目录下
server:
port: 8443
ssl:
enabled: ${SSL_ENABLED:true}
key-store: ${SSL_KEY_STORE:classpath:ssl/keystore.p12}
key-store-password: ${SSL_KEY_STORE_PASSWORD:myapptest}
keyStoreType: ${SSL_KEY_STORE_TYPE:PKCS12}
keyAlias: ${SSL_KEY_ALIAS:myapp}
启动服务即可通过https访问了,默认可以设置成false
3、配置docker容器,启动https
把证书放在ssl目录下
version: "3"
services:
test-https:
image: openjdk:8-jdk
container_name: test-https
restart: always
ports:
- 22443:22443
command: java -jar /opt/test-https.jar
volumes:
- /home/services/test/:/opt/
- /home/services/test/config/:/config/
- /home/services/test/ssl/:/ssl/
- /home/services/test/template_server/:/template_server/
- /home/services/test/patch/:/patch/
- /home/log/test/:/logs/
environment:
- TZ=Asia/Shanghai
- SERVICE_HOST=${HOST_IP}
- server.port=22443
- NACOS_NAMESPACE=${NACOS_NAMESPACE}
- NACOS_ADDR=${NACOS_ADDR}
#开启https,如果不开启则配置为false
- SSL_ENABLED=true
#以下配置根据实际证书配置
- SSL_KEY_STORE=ssl/keystore.p12
- SSL_KEY_STORE_PASSWORD=myapptest
- SSL_KEY_STORE_TYPE=PKCS12
- SSL_KEY_ALIAS=myapp
- JAVA_OPTS=-Xmx512m -XX:G1ConcRefinementThreads=4 -XX:MaxDirectMemorySize=1G
二、通过httpinvoke方法https服务
跳过证书校验
public class HttpInvokerRequestExecutorWithSession extends SimpleHttpInvokerRequestExecutor {
private int connectTimeout=0;
private int readTimeout=0;
private SSLContext sslContext;
private HostnameVerifier hostnameVerifier;
private void initSsl() {
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
}}, new SecureRandom());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
logger.error("ssl init error:",e);
throw new MsrRuntimeException(e.getMessage());
}
hostnameVerifier = (hostname, session) -> true;
}
/**
*
* (non-Javadoc)
*
* @see org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor
* #prepareConnection(java.net.HttpURLConnection, int)
*/
protected void prepareConnection(HttpURLConnection con, int contentLength) throws IOException {
super.prepareConnection(con, contentLength);
if (con instanceof HttpsURLConnection) {
if (sslContext == null) {
initSsl();
}
((HttpsURLConnection) con).setSSLSocketFactory(sslContext.getSocketFactory());
((HttpsURLConnection) con).setHostnameVerifier(hostnameVerifier);
}
con.setConnectTimeout(connectTimeout);
con.setReadTimeout(readTimeout);
}
/**
*
* (non-Javadoc)
*
* @see org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor
* #validateResponse(org.springframework.remoting.httpinvoker.HttpInvokerClientConfiguration,
* java.net.HttpURLConnection)
*/
protected void validateResponse(HttpInvokerClientConfiguration config, HttpURLConnection con)
throws IOException {
super.validateResponse(config, con);
}
public int getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
public int getReadTimeout() {
return readTimeout;
}
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
}
三、feign接口调用https服务
跳过证书校验。feign接口的地址还是正常配置http或https都支持
import feign.Client;
import feign.Contract;
import feign.RequestInterceptor;
import feign.codec.ErrorDecoder;
import feign.jaxrs.JAXRSContract;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
@Configuration
public class FeignConfiguration {
@Autowired
private BusinessConfig businessConfig;
/**
* yaml中的配置未生效,暂时在配置类中配置
*/
@Bean
public Contract getFeignContract() {
return new JAXRSContract();
}
@Bean
public ErrorDecoder getFeignErrorDecoder() {
return new FeignExceptionDecoder();
}
@Bean
public OkHttpClient okHttpClient() {
if(businessConfig.getRootServiceUrl() != null && businessConfig.getRootServiceUrl().contains("https")){
try {
TrustManager[] trustManagers = getTrustManager();
if (trustManagers == null || trustManagers.length == 0) {
throw new IllegalStateException("Failed to create trust managers");
}
SSLSocketFactory sslSocketFactory = getSSLSocketFactory();
if (sslSocketFactory == null) {
throw new IllegalStateException("Failed to initialize SSL socket factory");
}
return new OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool())
.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustManagers[0])
.hostnameVerifier((hostname, session) -> true)
.build();
} catch (Exception e) {
throw new RuntimeException("Failed to create OkHttpClient", e);
}
}
return new OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool())
.build();
}
@Bean
public RequestInterceptor requestInterceptor() {
return new CustomRequestInterceptor(businessConfig);
}
@Bean
public Client feignClient(OkHttpClient okHttpClient) {
return new CustomClient(new feign.okhttp.OkHttpClient(okHttpClient));
}
private TrustManager[] getTrustManager() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
return trustAllCerts;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private SSLSocketFactory getSSLSocketFactory() {
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, getTrustManager(), new SecureRandom());
return sc.getSocketFactory();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}