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.propertiesapplication.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);
        }
    }

}
相关推荐
武子康2 小时前
Java-07 深入浅出 MyBatis数据库一对多关系模型实战:表结构设计与查询实现
java·后端
花椒技术3 小时前
企业内部 Agent 落地复盘:Gateway、Skill 和二次确认如何串起受控业务执行
后端·agent·ai编程
我是一颗柠檬5 小时前
【MySQL全面教学】MySQL事务与ACID Day9(2026年)
数据库·后端·mysql
枕星而眠5 小时前
数据结构八大排序详解(一):四大简单排序
c语言·数据结构·c++·后端
IT_陈寒5 小时前
React useEffect闭包陷阱差点把我整失业了
前端·人工智能·后端
苍何5 小时前
爆肝两周,我把 Codex 最全实战指南开源了
后端
苏渡苇6 小时前
服务容错的必要性与Spring Cloud Alibaba Sentinel 限流配置实战
spring boot·spring cloud·sentinel
bug菌6 小时前
【SpringBoot 3.x 第254节】夯爆了,数据库访问性能优化实战详解!
数据库·spring boot·后端
Rust研习社6 小时前
从碎片化到标准化:cargo-bp 如何重构 Rust 开发逻辑
后端·rust·编程语言
锋行天下6 小时前
一句mysql复杂查询搞崩一个壮汉
后端·mysql·go