You need to enable JavaScript to run this app.
导航
HTTP接入
最近更新时间:2024.07.12 14:50:44首次发布时间:2024.07.12 14:50:44

1.确认需要的参数
access_key:BDxxxxx
secret_key:xxxxx
domain:域名
account:绑定的用户名

access_key,secret_key,domain 获取方式见接入须知
注意:使用OpenApi时,CDP资源权限与此绑定账户权限相关联,请勿越权访问

2. 以请求分群列表为例

代码依赖 3 提供的 Sign 代码

2.1 基于 STS 鉴权的方式请求

  1. 获取 STS Token

获取 token 请求接口:

curl -X GET --location "https://e0-0-80cdp.datarangers-onpremise.volces.com/open_platform/openapi?account=admin&duration_seconds=3000&Action=QueryOpenPlatformOpenApi&Version=2021-12-16&ApiAction=getUserToken&ApiVersion=2023-10-19" \
    -H "Accept: application/json" \
    -H "Host: e0-0-80cdp.datarangers-onpremise.volces.com" \
    -H "X-Date: 20240122T100402Z" \
    -H "X-Content-Sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" \
    -H "Authorization: HMAC-SHA256 Credential=BDPPd6be69d8697587c8cd245f9bb32b9fcc/20240122/cn/openPlatform/request, SignedHeaders=host;x-content-sha256;x-date, Signature=c686da0f3235cc164839cd0db9b175f56d2d807aafcaa6d7f5342719a5ed41cf"
  1. 签名过程:
    1. 获取 X-Date
String xDate = Sign.getXDate(new Date()); // 20240122T100402Z
2. 将请求体 body 转为 byte[]
byte[] bytes = Sign.body2Bytes(body); // body 为 null
3. 获取 X-Content-Sha256
String content = Sign.hashSHA256(bytes); // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
4. 构建 Authorization:
static String ak = "BDPPd6be69d8697587c8cd245f9bb32b9fcc";
static String sk = "632be27e66a8a07dd1c94c93fd8b8a6";
static String path = "https://xxxx/open_platform/openapi";

static String host = "e0-0-80cdp.datarangers-onpremise.volces.com";

Sign sign = new Sign("cn", "openPlatform", "http", host, ak, sk);
String auth = sign.getAuthorization("GET", new HashMap<>() {{
    put("account", "admin");
    put("duration_seconds", "3000");
    put("Action", "QueryOpenPlatformOpenApi");
    put("Version", "2021-12-16");
    put("ApiAction", "getUserToken");
    put("ApiVersion", "2023-10-19");
}}, bytes, xDate); // HMAC-SHA256 Credential=BDPPd6be69d8697587c8cd245f9bb32b9fcc/20240122/cn/openPlatform/request, SignedHeaders=host;x-content-sha256;x-date, Signature=c686da0f3235cc164839cd0db9b175f56d2d807aafcaa6d7f5342719a5ed41cf
  1. 拼接请求获得结果:
{
  "code": 0,
  "message": "",
  "msg": "success",
  "data": {
    "current_time": "2024-01-22T18:04:21.325+08:00",
    "expired_time": "2024-01-22T18:54:21.325+08:00",
    "access_key": "BDPPa98d1e65418b880ba525a0267a73138a",
    "secret_key": "fb757c8db975fef79d440bb5f11c8454",
    "session_token": "STSeyJhdXRoX29iamVjdF9pZCI6MywiZXhwaXJlZF90aW1lIjoiMjAyNC0wMS0yMlQxODo1NDoyMS4zMjUrMDg6MDAiLCJhdXRob3JpemVkX3Byb2plY3RfaWRzIjpbMV0sImFjY291bnQiOiJhZG1pbiIsInNpZ25hdHVyZSI6IjMwNDYwMjIxMDBkYjM3YzQ4YTU1NDJhNWY1NzA0YjYyYzRlY2MxMzYzZGRhNTU5OTQyNzBiYWFmNGJmNzcyNzc0YmViYTQ2M2FlMDIyMTAwZDg1NjI4YjBmOTM2NDg1MTU2Y2I4MDMwMzRmNDA1YTI5MDEwNzgwN2UyYTRjYWU3OGJkOTE3MmI4MTkwZDlhZSJ9"
  }
}
  1. 使用 STS 接口获取的临时 token,请求获取分群列表接口
curl -X GET --location "https://e0-0-80cdp.datarangers-onpremise.volces.com/open_platform/openapi?current=1&pageSize=10&tenantId=1&Action=QueryOpenPlatformOpenApi&Version=2021-12-16&ApiAction=legacyGetSegmentList&ApiVersion=2023-02-10" \
    -H "Accept: application/json" \
    -H "X-Date: 20240122T100923Z" \
    -H "X-Content-Sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" \
    -H "Authorization: HMAC-SHA256 Credential=BDPPa98d1e65418b880ba525a0267a73138a/20240122/cn/openPlatform/request, SignedHeaders=host;x-content-sha256;x-date, Signature=b86830497879b7aba0347e513a32a834c7b817ca9be5b9a369f7ed66dbbde6f7" \
    -H "X-Cdp-Security-Token: STSeyJhdXRoX29iamVjdF9pZCI6MywiZXhwaXJlZF90aW1lIjoiMjAyNC0wMS0yMlQxODo1NDoyMS4zMjUrMDg6MDAiLCJhdXRob3JpemVkX3Byb2plY3RfaWRzIjpbMV0sImFjY291bnQiOiJhZG1pbiIsInNpZ25hdHVyZSI6IjMwNDYwMjIxMDBkYjM3YzQ4YTU1NDJhNWY1NzA0YjYyYzRlY2MxMzYzZGRhNTU5OTQyNzBiYWFmNGJmNzcyNzc0YmViYTQ2M2FlMDIyMTAwZDg1NjI4YjBmOTM2NDg1MTU2Y2I4MDMwMzRmNDA1YTI5MDEwNzgwN2UyYTRjYWU3OGJkOTE3MmI4MTkwZDlhZSJ9"
  1. 签名过程:
    1. 获取 X-Date
String xDate = Sign.getXDate(new Date()); // 20240122T100923Z
2. 将请求体 body 转为 byte[]
byte[] bytes = Sign.body2Bytes(body); // body 为 null
3. 获取 X-Content-Sha256
String content = Sign.hashSHA256(bytes); // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
4. 构建 Authorization:
static String ak = "BDPPa98d1e65418b880ba525a0267a73138a";
static String sk = "fb757c8db975fef79d440bb5f11c8454";
static String path = "https://xxxx/open_platform/openapi";

static String host = "e0-0-80cdp.datarangers-onpremise.volces.com";

Sign sign = new Sign("cn", "openPlatform", "http", host, ak, sk);
String auth = sign.getAuthorization("GET", new HashMap<>() {{
    put("current", "1");
    put("pageSize", "10");
    put("tenantId", "1");
    put("Action", "QueryOpenPlatformOpenApi");
    put("Version", "2021-12-16");
    put("ApiAction", "legacyGetSegmentList");
    put("ApiVersion", "2023-02-10");
}}, bytes, xDate); // HMAC-SHA256 Credential=BDPPa98d1e65418b880ba525a0267a73138a/20240122/cn/openPlatform/request, SignedHeaders=host;x-content-sha256;x-date, Signature=b86830497879b7aba0347e513a32a834c7b817ca9be5b9a369f7ed66dbbde6f7
  1. 拼接请求获得结果上面的完整请求,其中 X-Cdp-Security-Token 头内容为 STS 接口中返回的 session_token 字段。

注意,获取临时 Token 的有效期在返回结果中 expired_time 字段,请尽量重复使用临时 Token 而不是反复获取 Token,以提高效率;

2.2 传统使用方式-已废弃

使用渠道账号中注册得到的 AK,SK,使用具体方法和 2.1 中签名获取 STS Token 的过程相同。

3. 附代码
import com.squareup.okhttp.RequestBody;
import okio.Buffer;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;

import static java.util.HexFormat.*;

/**
 * Copyright (year) Beijing Volcano Engine Technology Ltd.
 * 



 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 



 * http://www.apache.org/licenses/LICENSE-2.0
 * 



 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

public class Sign {

    private static final BitSet URLENCODER = new BitSet(256);

    private static final String CONST_ENCODE = "0123456789ABCDEF";
    public static final Charset UTF_8 = StandardCharsets.UTF_8;

    private final String region;
    private final String service;
    private final String schema;
    private final String host;
    private final String path;
    private final String ak;
    private final String sk;

    static {
        int i;
        for (i = 97; i <= 122; ++i) {
            URLENCODER.set(i);
        }

        for (i = 65; i <= 90; ++i) {
            URLENCODER.set(i);
        }

        for (i = 48; i <= 57; ++i) {
            URLENCODER.set(i);
        }
        URLENCODER.set('-');
        URLENCODER.set('_');
        URLENCODER.set('.');
        URLENCODER.set('~');
    }

    public static byte[] body2Bytes(RequestBody body){
        if (body == null) {
            return new byte[0];
        }
        try {
            final Buffer buffer = new Buffer();
            body.writeTo(buffer);
            return buffer.readByteArray();
        } catch (final Exception e) {
            return new byte[0];
        }
    }

    public Sign(String region, String service, String schema, String host,  String ak, String sk) {
        this.region = region;
        this.service = service;
        this.host = host;
        this.schema = schema;
        this.path = "/open_platform/openapi";
        this.ak = ak;
        this.sk = sk;
    }

    public static String getXDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        return sdf.format(date);
    }

    public String getAuthorization(String method, Map queryList, byte[] body, String xDate) throws Exception {
        if (body == null) {
            body = new byte[0];
        }
        String xContentSha256 = hashSHA256(body);
        String shortXDate = xDate.substring(0, 8);

        String signHeader = "host;x-content-sha256;x-date";


        SortedMap realQueryList = new TreeMap<>(queryList);
        StringBuilder querySB = new StringBuilder();
        for (String key : realQueryList.keySet()) {
            querySB.append(signStringEncoder(key))
                    .append("=")
                    .append(signStringEncoder(realQueryList.get(key)))
                    .append("&");
        }
        querySB.deleteCharAt(querySB.length() - 1);

        String canonicalStringBuilder = method + "\n" + path + "\n" + querySB + "\n" + "host:" + host + "\n" + "x-content-sha256:" + xContentSha256 + "\n" + "x-date:" + xDate + "\n" + "\n" + signHeader + "\n" + xContentSha256;

        System.out.println(canonicalStringBuilder);

        String hashcanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
        String credentialScope = shortXDate + "/" + region + "/" + service + "/request";
        String signString = "HMAC-SHA256" + "\n" + xDate + "\n" + credentialScope + "\n" + hashcanonicalString;

        byte[] signKey = genSigningSecretKeyV4(sk, shortXDate, region, service);
        String signature = of().formatHex(hmacSHA256(signKey, signString));



        URL url = new URL(schema + "://" + host + path + "?" + querySB);

        return "HMAC-SHA256" + " Credential=" + ak + "/" + credentialScope + ", SignedHeaders=" + signHeader + ", Signature=" + signature;
    }

    private String signStringEncoder(String source) {
        if (source == null) {
            return null;
        }
        StringBuilder buf = new StringBuilder(source.length());
        ByteBuffer bb = UTF_8.encode(source);
        while (bb.hasRemaining()) {
            int b = bb.get() & 255;
            if (URLENCODER.get(b)) {
                buf.append((char) b);
            } else if (b == 32) {
                buf.append("%20");
            } else {
                buf.append("%");
                char hex1 = CONST_ENCODE.charAt(b >> 4);
                char hex2 = CONST_ENCODE.charAt(b & 15);
                buf.append(hex1);
                buf.append(hex2);
            }
        }

        return buf.toString();
    }

    public static String hashSHA256(byte[] content) throws Exception {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");

            return of().formatHex(md.digest(content));
        } catch (Exception e) {
            throw new Exception("Unable to compute hash while signing request: " + e.getMessage(), e);
        }
    }

    public static byte[] hmacSHA256(byte[] key, String content) throws Exception {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(key, "HmacSHA256"));
            return mac.doFinal(content.getBytes());
        } catch (Exception e) {
            throw new Exception("Unable to calculate a request signature: " + e.getMessage(), e);
        }
    }

    private byte[] genSigningSecretKeyV4(String secretKey, String date, String region, String service) throws Exception {
        byte[] kDate = hmacSHA256((secretKey).getBytes(), date);
        byte[] kRegion = hmacSHA256(kDate, region);
        byte[] kService = hmacSHA256(kRegion, service);
        return hmacSHA256(kService, "request");
    }
}