构造JAVA安全客户端
这里不使用spring-data-elasticsearch,使用原生REST API调用
spring-data-elasticsearch底层依赖的是TransportClient,TransportClient在ES7中已被弃用,取而代之的是 Java 高级 REST 客户端,并将在 Elasticsearch 8.0 中删除。
引入依赖
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>${es-version}</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>${es-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.11</version>
</dependency>
增加配置项
elasticsearch:
# es登录名
username: elastic
# es登录密码
password: 123456
# 调用es的apikey接口生成,注意,实际取的是encoded字段,在创建完时会返回,实际上其对应的是base64.encode(id:api_key)
# "encoded":"UGxYVHo0WUJ1TEIzb2pCZ0piY1Y6NHZYODRmQVBSQm1TVm9Vd2xLMGxsZw=="
# CreateApiKeyResponse: {"api_key":"4vX84fAPRBmSVoUwlK0llg","id":"PlXTz4YBuLB3ojBgJbcV","name":"my-es-apikey","encoded":"UGxYVHo0WUJ1TEIzb2pCZ0piY1Y6NHZYODRmQVBSQm1TVm9Vd2xLMGxsZw=="}
apiKey: UGxYVHo0WUJ1TEIzb2pCZ0piY1Y6NHZYODRmQVBSQm1TVm9Vd2xLMGxsZw==
# http fingerprint,es第一次初始化时获取
fingerprint: 8cbf9aaba0b5b168afae69473a5ffac5f76f7d62dfbcd7cda25451a825a07faf
# 配置es集群服务端地址
hosts: [https://127.0.0.1:9201,https://127.0.0.1:9202,https://127.0.0.1:9203]
# es 证书存放路径
certPath: /certs/http_ca.crt
📌相关配置信息,见es初始化后的配置信息
- apiKey可调用REST API生成,expiration表示apiKey只有一天有效期,不传表示永久,我们最终需要的字段为加密后encoded
b.certPath表示证书路径,复制es节点任意目录下的证书文件
es节点安装目录/config/certs/http_ca.crt
放到项目下src/main/resources/certs/http_ca.crt
增加配置类
package com.strap.mydemo.config;
import cn.hutool.core.collection.CollectionUtil;
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.strap.mydemo.utils.TransportUtils;
import lombok.Data;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* <p>加载es相关配置</p>
*
* @author strap
*/
@Configuration
@ConfigurationProperties(prefix = "elasticsearch")
@Data
public class EsConfig {
/**
* 鉴权请求头
*/
private static final String AUTHORIZATION_HEADER_NAME = "Authorization";
/**
* 鉴权请求头值前缀
*/
private static final String AUTHORIZATION_HEADER_VALUE_PREFIX = "ApiKey ";
/**
* es服务端host
*/
private List<String> hosts;
/**
* es登录用户名
*/
private String username;
/**
* es登录密码
*/
private String password;
/**
* 通过es请求获取的apiKey
*/
private String apiKey;
/**
* es初始化获取的http fingerprint,配合https认证使用
*/
private String fingerprint;
/**
* es服务端证书存放路径
*/
private String certPath;
public EsConfig() {
}
/**
* 获取host
*
* @return host数据
*/
public HttpHost[] generateHosts() {
if (CollectionUtil.isEmpty(hosts)) {
throw new IllegalArgumentException("hosts cannot be empty");
}
return hosts.stream().map(HttpHost::create).toArray(HttpHost[]::new);
}
/**
* 不同方式加载sslContext
*
* @param fingerprint true 使用http fingerprint来加载sslContext / false 使用证书加载
* @return 获取sslContext
*/
private SSLContext getSSLContext(boolean fingerprint) {
if (fingerprint) {
return TransportUtils.sslContextFromCaFingerprint(getFingerprint());
} else {
try (
InputStream is = getClass().getResourceAsStream(getCertPath())
) {
return TransportUtils.sslContextFromHttpCaCrt(is);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* 使用不同方式构建restClient
*
* @param fingerprint true 则使用http fingerprint / false 使用证书
* @param authenticateByUser true 使用帐号认证 / false 使用apiKey认证
* @param authenticate true 需要安全认证 / false 不需要安全认证
* @return restClient 加载异常
*/
private RestClient buildRestClient(boolean fingerprint, boolean authenticateByUser, boolean authenticate) {
RestClientBuilder clientBuilder = RestClient.builder(generateHosts());
if (authenticate) {
if (authenticateByUser) {
BasicCredentialsProvider userCre = new BasicCredentialsProvider();
userCre.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(getUsername(), getPassword()));
clientBuilder
.setHttpClientConfigCallback(h -> h
.setSSLContext(getSSLContext(fingerprint))
.setDefaultCredentialsProvider(userCre)
);
} else {
clientBuilder
.setHttpClientConfigCallback(h -> h.setSSLContext(getSSLContext(fingerprint)))
.setDefaultHeaders(new Header[]{new BasicHeader(AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE_PREFIX + getApiKey())});
}
}
return clientBuilder.build();
}
/**
* 不需要鉴权直接使用hosts连接
*/
private RestClient buildSimpleRestClient() {
return buildRestClient(false, false, false);
}
/**
* 不需要安全认证获取client
*/
@Bean(name = "simpleClient")
public ElasticsearchClient getSimpleClient() throws Exception {
RestClientTransport restClientTransport = new RestClientTransport(buildSimpleRestClient(), new JacksonJsonpMapper());
return new ElasticsearchClient(restClientTransport);
}
/**
* 使用apiKey获取客户端
*/
@Bean(name = "apiKeyClient")
public ElasticsearchClient getClientByApiKey() {
RestClient restClient = buildRestClient(false, false, true);
RestClientTransport restClientTransport = new RestClientTransport(restClient, new JacksonJsonpMapper());
return new ElasticsearchClient(restClientTransport);
}
/**
* 使用用户认证获取客户端
*/
@Bean(name = "userClient")
public ElasticsearchClient getClientByUser() {
RestClient restClient = buildRestClient(true, true, true);
RestClientTransport restClientTransport = new RestClientTransport(restClient, new JacksonJsonpMapper());
return new ElasticsearchClient(restClientTransport);
}
/**
* 获取异步处理client,同样也支持各类认证方式,这里只举例一种
*/
@Bean(name = "asyncClient")
public ElasticsearchAsyncClient getAsyncClientByUser() {
RestClient restClient = buildRestClient(false, true, true);
RestClientTransport restClientTransport = new RestClientTransport(restClient, new JacksonJsonpMapper());
return new ElasticsearchAsyncClient(restClientTransport);
}
}
注入获取不同方式认证的client
/**
* 调用不同client
* 如@Resource(name = "apiKeyClient")
* 如@Resource(name = "userClient")
*/
@Resource(name = "apiKeyClient")
private ElasticsearchClient client;