三、Elasticsearch构造JAVA安全客户端

构造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初始化后的配置信息

  1. 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;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值