diff --git a/cf-framework/cf-spring-boot-starter-elasticsearch/src/main/java/com/cf/imes/framework/es/config/ChenfengElasticsearchAutoConfiguration.java b/cf-framework/cf-spring-boot-starter-elasticsearch/src/main/java/com/cf/imes/framework/es/config/ChenfengElasticsearchAutoConfiguration.java index 48a4b2a63..6c4b9752f 100644 --- a/cf-framework/cf-spring-boot-starter-elasticsearch/src/main/java/com/cf/imes/framework/es/config/ChenfengElasticsearchAutoConfiguration.java +++ b/cf-framework/cf-spring-boot-starter-elasticsearch/src/main/java/com/cf/imes/framework/es/config/ChenfengElasticsearchAutoConfiguration.java @@ -4,16 +4,42 @@ import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient; import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.transport.rest_client.RestClientTransport; +import com.cf.imes.framework.common.util.encrypt.AesUtils; import com.cf.imes.framework.es.core.service.ESDocumentService; import com.cf.imes.framework.es.core.service.ESDocumentServiceImpl; +import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.core.io.ClassPathResource; import org.springframework.util.StringUtils; +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; + /** * @author there @@ -21,20 +47,19 @@ import org.springframework.util.StringUtils; @AutoConfiguration @ConditionalOnClass(ElasticsearchClient.class) @EnableConfigurationProperties(EsProperties.class) +@Slf4j public class ChenfengElasticsearchAutoConfiguration { - //超时时间设置 - public static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 10000; - public static final int DEFAULT_SOCKET_TIMEOUT_MILLIS = 300000; - public static final int DEFAULT_CONNECT_REQUEST_TIMEOUT_MILLIS = 1000; + @Value("${chenfeng.encrypt.publicKey:}") + private String publicKey; /** * 同步方式 * */ @Bean - public ElasticsearchClient elasticsearchClient(EsProperties properties) { - return new ElasticsearchClient(getTransport(properties.getUris())); + public ElasticsearchClient elasticsearchClient(RestClientTransport transport) { + return new ElasticsearchClient(transport); } /** @@ -42,44 +67,110 @@ public class ChenfengElasticsearchAutoConfiguration { * */ @Bean - public ElasticsearchAsyncClient elasticsearchAsyncClient(EsProperties properties) { - return new ElasticsearchAsyncClient(getTransport(properties.getUris())); + public ElasticsearchAsyncClient elasticsearchAsyncClient(RestClientTransport transport) { + return new ElasticsearchAsyncClient(transport); } @Bean - private ESDocumentService esDocumentService(ElasticsearchClient elasticsearchClient, ElasticsearchAsyncClient elasticsearchAsyncClient) { + public ESDocumentService esDocumentService(ElasticsearchClient elasticsearchClient, ElasticsearchAsyncClient elasticsearchAsyncClient) { return new ESDocumentServiceImpl(elasticsearchClient, elasticsearchAsyncClient); } /** * 获取客户端 RestClientTransport */ - private RestClientTransport getTransport(String hosts){ - HttpHost[] httpHosts = toHttpHost(hosts); - RestClient restClient = getRestClient(httpHosts); - return new RestClientTransport(restClient, new JacksonJsonpMapper()); + @Bean + public RestClientTransport getTransport(RestClient client){ + return new RestClientTransport(client, new JacksonJsonpMapper()); } + /** * 获取客户端RestClient - * @param httpHosts http数组 + * chenfeng.encrypt.enable:true + * + * @param properties es配置 */ - private RestClient getRestClient(HttpHost[] httpHosts){ - return RestClient.builder(httpHosts).setRequestConfigCallback(requestConfigBuilder -> { - requestConfigBuilder.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT_MILLIS); - requestConfigBuilder.setSocketTimeout(DEFAULT_SOCKET_TIMEOUT_MILLIS); - requestConfigBuilder.setConnectionRequestTimeout(DEFAULT_CONNECT_REQUEST_TIMEOUT_MILLIS); + @Bean + @ConditionalOnProperty(name = "chenfeng.encrypt.enable", havingValue = "true") + public RestClient getAuthRestClient(EsProperties properties) { + // 配置账号密码 + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, + new UsernamePasswordCredentials(AesUtils.decrypt(properties.getUsername(), publicKey), AesUtils.decrypt(properties.getPassword(), publicKey))); + RestClientBuilder.HttpClientConfigCallback httpClientConfigCallback = httpClientBuilder -> { + // 设置账号密码、连接信息 + HttpAsyncClientBuilder httpAsyncClientBuilder = httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider) + .setDefaultRequestConfig(RequestConfig.custom() + .setConnectTimeout(properties.getConnectionTimeout().toSecondsPart()) + .setSocketTimeout(properties.getSocketTimeout().toSecondsPart()) + .setConnectionRequestTimeout(properties.getConnectionRequestTimeout().toSecondsPart()) + .build()); + if (properties.isSecurityHttpSslEnable()) { + // 开启ssl配置连接证书 + httpAsyncClientBuilder.setSSLContext(buildSSLContext()).setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE); + } + return httpAsyncClientBuilder; + }; + return RestClient.builder(toHttpHost(properties.getUris(), properties.isSecurityHttpSslEnable())).setHttpClientConfigCallback(httpClientConfigCallback).build(); + } + + /** + * 获取客户端RestClient(默认) + * chenfeng.encrypt.enable:false或者缺省 + * + * @param properties es配置 + */ + @Bean + @ConditionalOnProperty(name = "chenfeng.encrypt.enable", havingValue = "false", matchIfMissing = true) + public RestClient getRestClient(EsProperties properties) { + return RestClient.builder(toHttpHost(properties.getUris(), properties.isSecurityHttpSslEnable())).setRequestConfigCallback(requestConfigBuilder -> { + requestConfigBuilder.setConnectTimeout(properties.getConnectionTimeout().toSecondsPart()); + requestConfigBuilder.setSocketTimeout(properties.getSocketTimeout().toSecondsPart()); + requestConfigBuilder.setConnectionRequestTimeout(properties.getConnectionRequestTimeout().toSecondsPart()); return requestConfigBuilder; }).build(); } /** - * 解析配置的字符串hosts,转为HttpHost对象数组 + * 构建ssl请求信息 + * + * @return */ - private HttpHost[] toHttpHost(String hosts) { + private SSLContext buildSSLContext() { + SSLContext sslContext = null; + try { + ClassPathResource resource = new ClassPathResource("http_ca.crt"); + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + Certificate trustedCa; + try (InputStream is = resource.getInputStream()) { + trustedCa = factory.generateCertificate(is); + } + KeyStore trustStore = KeyStore.getInstance("pkcs12"); + trustStore.load(null, null); + trustStore.setCertificateEntry("ca", trustedCa); + SSLContextBuilder sslContextBuilder = SSLContexts.custom() + .loadTrustMaterial(trustStore, null); + sslContext = sslContextBuilder.build(); + } catch (CertificateException | IOException | KeyStoreException | NoSuchAlgorithmException | + KeyManagementException e) { + log.error("ES连接认证失败", e); + } + return sslContext; + } + + + /** + * 解析域名 + * + * @param hosts 域名字符串 + * @param isSslEnable 是否开启ssl + * @return + */ + private HttpHost[] toHttpHost(String hosts, boolean isSslEnable) { if (!StringUtils.hasLength(hosts)) { - throw new RuntimeException("invalid elasticsearch configuration. elasticsearch.hosts不能为空!"); + throw new IllegalArgumentException("invalid elasticsearch configuration. elasticsearch.hosts不能为空!"); } // 多个IP逗号隔开 String[] hostArray = hosts.split(","); @@ -87,14 +178,9 @@ public class ChenfengElasticsearchAutoConfiguration { HttpHost httpHost; for (int i = 0; i < hostArray.length; i++) { String[] strings = hostArray[i].split(":"); - httpHost = new HttpHost(strings[0], Integer.parseInt(strings[1]), "http"); + httpHost = new HttpHost(strings[0], Integer.parseInt(strings[1]), isSslEnable ? "https" : "http"); httpHosts[i] = httpHost; } - return httpHosts; } - - - - } diff --git a/cf-framework/cf-spring-boot-starter-elasticsearch/src/main/java/com/cf/imes/framework/es/config/EsProperties.java b/cf-framework/cf-spring-boot-starter-elasticsearch/src/main/java/com/cf/imes/framework/es/config/EsProperties.java index 8030fc5d3..5dfd0a99f 100644 --- a/cf-framework/cf-spring-boot-starter-elasticsearch/src/main/java/com/cf/imes/framework/es/config/EsProperties.java +++ b/cf-framework/cf-spring-boot-starter-elasticsearch/src/main/java/com/cf/imes/framework/es/config/EsProperties.java @@ -2,12 +2,46 @@ package com.cf.imes.framework.es.config; import org.springframework.boot.context.properties.ConfigurationProperties; +import java.time.Duration; + /** * es环境配置 * @author there */ @ConfigurationProperties(prefix = "spring.elasticsearch") public class EsProperties { + private String uris; + + /** + * Username for authentication with Elasticsearch. + */ + private String username; + + /** + * Password for authentication with Elasticsearch. + */ + private String password; + + /** + * Connection timeout used when communicating with Elasticsearch. + */ + private Duration connectionTimeout = Duration.ofSeconds(10); + + /** + * Socket timeout used when communicating with Elasticsearch. + */ + private Duration socketTimeout = Duration.ofSeconds(30); + + + private Duration connectionRequestTimeout = Duration.ofSeconds(1); + + /** + * Prefix added to the path of every request sent to Elasticsearch. + */ + private String pathPrefix; + + private boolean securityHttpSslEnable = false; + public String getUris() { return uris; } @@ -16,5 +50,59 @@ public class EsProperties { this.uris = uris; } - private String uris; + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Duration getConnectionTimeout() { + return this.connectionTimeout; + } + + public void setConnectionTimeout(Duration connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + public Duration getSocketTimeout() { + return this.socketTimeout; + } + + public void setSocketTimeout(Duration socketTimeout) { + this.socketTimeout = socketTimeout; + } + + public String getPathPrefix() { + return this.pathPrefix; + } + + public void setPathPrefix(String pathPrefix) { + this.pathPrefix = pathPrefix; + } + + public boolean isSecurityHttpSslEnable() { + return securityHttpSslEnable; + } + + public void setSecurityHttpSslEnable(boolean securityHttpSslEnable) { + this.securityHttpSslEnable = securityHttpSslEnable; + } + + public Duration getConnectionRequestTimeout() { + return connectionRequestTimeout; + } + + public void setConnectionRequestTimeout(Duration connectionRequestTimeout) { + this.connectionRequestTimeout = connectionRequestTimeout; + } } diff --git a/cf-framework/cf-spring-boot-starter-mybatis/src/main/java/com/cf/imes/framework/datasource/config/ChenfengDataSourceEncryptConfiguration.java b/cf-framework/cf-spring-boot-starter-mybatis/src/main/java/com/cf/imes/framework/datasource/config/ChenfengDataSourceEncryptConfiguration.java index 5fa1cd56c..fe12fc47f 100644 --- a/cf-framework/cf-spring-boot-starter-mybatis/src/main/java/com/cf/imes/framework/datasource/config/ChenfengDataSourceEncryptConfiguration.java +++ b/cf-framework/cf-spring-boot-starter-mybatis/src/main/java/com/cf/imes/framework/datasource/config/ChenfengDataSourceEncryptConfiguration.java @@ -15,9 +15,9 @@ import org.springframework.context.annotation.Bean; */ @AutoConfiguration @AutoConfigureBefore(DynamicDataSourceAutoConfiguration.class) +@ConditionalOnProperty(name = "chenfeng.encrypt.enable", havingValue = "true") public class ChenfengDataSourceEncryptConfiguration { @Bean - @ConditionalOnProperty(name = "chenfeng.encrypt.enable", havingValue = "true") public DataSourceInitEvent getDataSourceInitEvent() { return new ChenfengDataSourceEncryptInitEvent(); } diff --git a/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/config/ChenfengRedisEncryptAutoConfiguration.java b/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/config/ChenfengRedisEncryptAutoConfiguration.java index f1cd7435b..490d1ad50 100644 --- a/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/config/ChenfengRedisEncryptAutoConfiguration.java +++ b/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/config/ChenfengRedisEncryptAutoConfiguration.java @@ -20,13 +20,13 @@ import org.springframework.util.StringUtils; * @since 2024/8/27 9:46 */ @AutoConfiguration +@ConditionalOnProperty(name = "chenfeng.encrypt.enable", havingValue = "true") public class ChenfengRedisEncryptAutoConfiguration { @Value("${chenfeng.encrypt.publicKey:}") private String publicKey; @Bean - @ConditionalOnProperty(name = "chenfeng.encrypt.enable", havingValue = "true") public RedissonAutoConfigurationCustomizer redissonAutoConfigurationCustomizer() { return configuration -> { Config redissonConfig = new Config(); diff --git a/cf-module-infra/cf-module-infra-biz/src/main/resources/application.yaml b/cf-module-infra/cf-module-infra-biz/src/main/resources/application.yaml index 8041c9902..3f27b6988 100644 --- a/cf-module-infra/cf-module-infra-biz/src/main/resources/application.yaml +++ b/cf-module-infra/cf-module-infra-biz/src/main/resources/application.yaml @@ -157,5 +157,7 @@ chenfeng: - infra_job_log - infra_job_log - infra_data_source_config - + encrypt: + enable: false + publicKey: cfimes debug: false diff --git a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/application.yaml b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/application.yaml index df903d7ad..453122f78 100644 --- a/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/application.yaml +++ b/cf-module-prod-manage/cf-module-prod-manage-biz/src/main/resources/application.yaml @@ -161,5 +161,7 @@ chenfeng: send-maximum-quantity-per-day: 10 begin-code: 9999 # 这里配置 9999 的原因是,测试方便。 end-code: 9999 # 这里配置 9999 的原因是,测试方便。 - + encrypt: + enable: false + publicKey: cfimes debug: false diff --git a/cf-module-prod-plan/cf-module-prod-plan-biz/src/main/resources/application.yaml b/cf-module-prod-plan/cf-module-prod-plan-biz/src/main/resources/application.yaml index 6a587132c..07c6419b9 100644 --- a/cf-module-prod-plan/cf-module-prod-plan-biz/src/main/resources/application.yaml +++ b/cf-module-prod-plan/cf-module-prod-plan-biz/src/main/resources/application.yaml @@ -175,5 +175,7 @@ chenfeng: send-maximum-quantity-per-day: 10 begin-code: 9999 # 这里配置 9999 的原因是,测试方便。 end-code: 9999 # 这里配置 9999 的原因是,测试方便。 - + encrypt: + enable: false + publicKey: cfimes debug: false diff --git a/cf-module-report/cf-module-report-biz/src/main/resources/application.yaml b/cf-module-report/cf-module-report-biz/src/main/resources/application.yaml index 2486af452..13b2d085a 100644 --- a/cf-module-report/cf-module-report-biz/src/main/resources/application.yaml +++ b/cf-module-report/cf-module-report-biz/src/main/resources/application.yaml @@ -103,6 +103,8 @@ chenfeng: organ: # 多租户相关配置项 enable: true ignore-tables: - + encrypt: + enable: false + publicKey: cfimes debug: false