华为云lts日志接入指南&踩坑经历

本文介绍了如何接入华为云LTS日志查询功能,包括引入Maven依赖,设置SSL加密客户端以及请求签名的步骤。在实现过程中遇到了Signer实例化错误和请求参数配置错误,文中给出了相应的解决方案。同时,提出了代码优化建议,如创建OkHttpClient实例应作为单例以节省资源。
摘要由CSDN通过智能技术生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

需要接入华为云lts日志查询功能,但是lts请求需要token或者ak、sk加密才能请求成功。
华为云lts日志查询接口:POST /v2/{project_id}/groups/{log_group_id}/streams/{log_stream_id}/content/query


提示:以下是本篇文章正文内容,下面案例可供参考

一、接入步骤

1.引入maven配置

<!-- 华为云 LTS日志 -->
        <dependency>
            <groupId>com.huawei.apigateway</groupId>
            <artifactId>java-sdk-core</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.openeuler</groupId>
            <artifactId>bgmprovider</artifactId>
            <version>1.0.3</version>
        </dependency>

2.ssl加密客户端

package com.csdn.doaudit.tools;

import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.prng.SP800SecureRandomBuilder;
import org.openeuler.BGMProvider;

import javax.net.ssl.*;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

/**
 * ssl加密工具
 * @author hext
 * @version 1.0
 * @description
 * @date 2023/6/19
 */
@Slf4j
public class SSLCipherSuiteUtil {

    private static final int ENTROPY_BITS_REQUIRED = 384;

    private static final int CIPHER_LEN = 256;

    public static final String GM_PROTOCOL = "GMTLS";

    public static final String INTERNATIONAL_PROTOCOL = "TLSv1.2";

    public static final String SIGNATURE_ALGORITHM_SDK_HMAC_SHA256 = "SDK-HMAC-SHA256";
    public static final String[] SUPPORTED_CIPHER_SUITES = {"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
            "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
            "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"};

    private static OkHttpClient okHttpClient;

    private static CloseableHttpClient httpClient;

    public static OkHttpClient createOkHttpClient(String protocol) throws Exception {
        SSLContext sslContext = getSslContext(protocol);
        // Create an ssl socket factory with our all-trusting manager
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .sslSocketFactory(sslSocketFactory, new TrustAllManager())
                .hostnameVerifier(new TrustAllHostnameVerifier());
        okHttpClient = builder.connectTimeout(10, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).build();
        return okHttpClient;
    }

    public static HttpClient createHttpClient(String protocol) throws Exception {
        SSLContext sslContext = getSslContext(protocol);
        // create factory
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
                new String[]{protocol}, SUPPORTED_CIPHER_SUITES, new TrustAllHostnameVerifier());

        httpClient = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();
        return httpClient;
    }

    private static SSLContext getSslContext(String protocol) throws Exception,
            NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {
        if (!GM_PROTOCOL.equals(protocol) && !INTERNATIONAL_PROTOCOL.equals(protocol)) {
            log.info("Unsupport protocol: {}, Only support GMTLS TLSv1.2", protocol);
            throw new Exception("Unsupport protocol, Only support GMTLS TLSv1.2");
        }
        // Create a trust manager that does not validate certificate chains
        TrustAllManager[] trust = {new TrustAllManager()};
        KeyManager[] kms = null;
        SSLContext sslContext;

        sslContext = SSLContext.getInstance(INTERNATIONAL_PROTOCOL, "SunJSSE");

        if (GM_PROTOCOL.equals(protocol)) {
            Security.insertProviderAt(new BGMProvider(), 1);
            sslContext = SSLContext.getInstance(GM_PROTOCOL, "BGMProvider");
        }
        SecureRandom secureRandom = getSecureRandom();
        sslContext.init(kms, trust, secureRandom);
        sslContext.getServerSessionContext().setSessionCacheSize(8192);
        sslContext.getServerSessionContext().setSessionTimeout(3600);
        return sslContext;
    }

    // 不校验服务端证书
    private static class TrustAllManager implements X509TrustManager {
        private X509Certificate[] issuers;

        public TrustAllManager() {
            this.issuers = new X509Certificate[0];
        }

        public X509Certificate[] getAcceptedIssuers() {
            return issuers;
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }
    }

    private static SecureRandom getSecureRandom() {
        SecureRandom source;
        try {
            source = SecureRandom.getInstanceStrong();
        } catch (NoSuchAlgorithmException e) {
            log.error("get SecureRandom failed", e);
            throw new RuntimeException("get SecureRandom failed");
        }
        boolean predictionResistant = true;
        BlockCipher cipher = new AESEngine();
        boolean reSeed = false;
        return new SP800SecureRandomBuilder(source, predictionResistant).setEntropyBitsRequired(
                ENTROPY_BITS_REQUIRED).buildCTR(cipher, CIPHER_LEN, null, reSeed);
    }

    // 不校验域名
    private static class TrustAllHostnameVerifier implements HostnameVerifier {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
}

3.request签名请求

       Request request = new Request();
        request.setKey("ak");
        request.setSecret("sk");
        request.setMethod("POST");
        String formatUrl = "https://lts.%s.myhuaweicloud.com/v2/%s/groups/%s/streams/%s/content/query";
        String url = String.format(this.formatUrl, huaWeiLogConfig.getRegion(), huaWeiLogConfig.getProjectId(), huaWeiLogConfig.getLogGroupId(), logStreamId);
        request.setUrl(url);
        request.addHeader("Host", "lts." + huaWeiLogConfig.getRegion() + ".myhuaweicloud.com");
        request.addHeader("Content-Type", "application/json");
        JSONObject params = new JSONObject();
        params.put("start_time", startTime);
        params.put("end_time", endTime);
        params.put("keywords", query);
        // 不高亮
        params.put("highlight", false);
        request.setBody(params.toString());
        // Sign the request.
        okhttp3.Request signedRequest = Client.signOkhttp(request, SSLCipherSuiteUtil.SIGNATURE_ALGORITHM_SDK_HMAC_SHA256);
        OkHttpClient okHttpClient = SSLCipherSuiteUtil.createOkHttpClient(SSLCipherSuiteUtil.INTERNATIONAL_PROTOCOL);
       Response response = okHttpClient.newCall(request).execute();
       String result = response.body().string();
       log.info("result:{}", result);
       response.close();

二、遇到的问题

1.Signer实例化InstantiationError

提示Signer实例化InstantiationError(当一个应用试图通过Java的new操作符构造一个抽象类或者接口时抛出该异常.)
在这里插入图片描述
搜Singn发现有两个包也一样的类,不过一个是interface、一个是class。看来是运行时用的interface实例化才报的错
在这里插入图片描述
解决办法:找到Singn接口对应是哪个包,排除对应的jar包,以自己导入的版本为准
在这里插入图片描述

2.请求参数配置错误

华为云提供了调试接口,需配置正确的region、projectId、logGroupId、logStreamId,调试效果如下:
在这里插入图片描述
调试接口地址:https://console.huaweicloud.com/apiexplorer/#/openapi/LTS/debug?api=ListLogs

三、代码优化

创建OkHttpClient或httpClient是比较耗费资源的动作,不应该每次请求都创建一次,加载对象应该做成单例
代码如下:

package com.csdn.doaudit.utils;

import com.csdn.doaudit.tools.SSLCipherSuiteUtil;
import lombok.Getter;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import org.apache.http.client.HttpClient;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * SSL加密HttpClient端
 * @author hext
 * @version 1.0
 * @description
 * @date 2023/6/20
 */
@Component
public class SSLHttpClient implements InitializingBean, DisposableBean {

    @Getter
    private OkHttpClient okHttpClient;

//    @Getter
//    private HttpClient httpClient;

    @Override
    public void destroy() throws Exception {
        this.okHttpClient = null;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.okHttpClient = SSLCipherSuiteUtil.createOkHttpClient(SSLCipherSuiteUtil.INTERNATIONAL_PROTOCOL);
    }

    public Response execute(okhttp3.Request request) throws IOException {
        return this.okHttpClient.newCall(request).execute();
    }
}

使用时:

Response response = this.sslHttpClient.execute(signedRequest);

总结

1、lts日志查询的http请求需将ak、sk加密认证才能生效
2、避免jar包冲突,maven冲突需排除
3、可根据接口测试工具验证

参考文档

1、签名 sdk api:https://support.huaweicloud.com/devg-apisign/api-sign-sdk-java.html
2、接口文档:https://support.huaweicloud.com/api-lts/lts-api.pdf、https://support.huaweicloud.com/api-lts/lts_api_0028.html
3、接口测试地址:https://console.huaweicloud.com/apiexplorer/#/openapi/LTS/debug?api=ListLogs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值