增长分析(即DataFinder) 所有开放接口,均建议使用 https 进行通信。所有接口都需要经过统一的签名处理。为了方便集成和使用,DataFinder提供了 SDK,本文为您介绍DataFinder开发接口的签名机制和使用说明。
OpenAPI 的服务地址在中国区和非中国区是隔离不互通的,OpenAPI 的服务地址需要根据所在地区进行设置。
OpenAPI 使用 AK/SK 认证鉴权。
说明
AK是平台为每个集团默认创建的;SK全局唯一,自行输入(长度 6~64个字符),请获取后妥善保管。
AK/SK认证就是使用AK/SK对请求进行签名,在请求时将签名信息添加到消息头,从而通过身份认证。
请求发送方使用方式如下:
以 “ak-v1/access_key/timestamp/expiretime"为认证字符串前缀。
使用签名算法(HmacSHA256),以认证字符串前缀为消息,secret_key为密钥,生成字符串sign_key。
把需要加密的字段放入canonicalRequest,其格式为:
CanonicalRequest = HTTPMethod:${method} + '\n' + CanonicalURI:${uri} + '\n' + CanonicalQueryString:${queryString} + '\n' + CanonicalBody:${body}
使用签名算法(HmacSHA256),以canonicalRequest为消息,sign_key为密钥,生成字符串signature。
最终的认证字符串为 “ak-v1/access_key/timestamp/expiretime/signature”。
把认证字符串放在http的header:Authorization:ak-v1/access_key/timestamp/expiretime/signature
为了方便客户调用 OpenAPI, DataFinder提供了 OpenAPI SDK, 其主要功能是提供了对签名过程和复杂查询参数的包装。SDK 已经在 Github 上开源,建议使用Github 源码的方式。基本使用流程:
bc
来指一个RangersClient实例)ak = '{使用AK替换}' sk = '{使用SK替换}' # saas bc = RangersClient(ak, sk) # 海外使用非中国区的地址;私有化,需要制定下私有化的finder服务域名,请参考 “OpenAPI 概览”的服务地址说明。 url = '{使用非中国区或者Finder服务域名替换}' bc = RangersClient(ak, sk, url=url) # 调用具体的接口 bc.request("${path}",...)
相关接口说明(具体的方法名称在不同的语言上会有命名格式的区别):
bc.data_finder("${path}", ...)
, 相当于 bc.request("/datafinder/${path}", ...)
,即在path前,加上一个/datafinder的context-pathbc.data_rangers("${path}", ...)
, 相当于bc.request(/datarangers/${path}", ...)
,即在path前,加上一个/datarangers的context-pathbc.data_tester("${path}", ...)
, 相当于 bc.request("/datatester/${path}", ...)
,即在path前,加上一个/datatester的context-pathbc.data_profile("${path}", ...)
, 相当于 bc.request("/dataprofile/${path}", ...)
,即在path前,加上一个/dataprofile的context-pathbc.data_tracer("${path}", ...)
, 相当于 bc.request("/datatracer/${path}", ...)
,即在path前,加上一个/datatracer的context-path建议后续都使用bc.request
接口。
另外,OpenAPI 还提供了查询 DSL Builder,具体接口参考源码 API 说明。
String ak = "xxx";
String sk = "xxx";
// SDK 的默认url地址是指向中国区 SAAS 的
RangersClient bc = new RangersClient(ak, sk);
// 海外和私有化需要指定url地址, 可以参考 “OpenAPI 概览”
String url="{使用非中国区或者Finder服务域名替换}";
RangersClient bc = new RangersClient(ak, sk, url);
Python SDK 软件包的形式下载后在shell执行以下命令完成安装:
# python需要3.7及以上版本
pip install rangersdk-${version}.tar.gz
from rangersdk import RangersClient
ak = 'xxx' # ak
sk = 'xxx' # sk
bc = RangersClient(ak, sk)
# 海外和私有化需要指定url地址, 可以参考 “OpenAPI 概览”,
url = '{使用非中国区或者Finder服务域名替换}'
# 注意这里传参数,一定要写成 url=url
bc = RangersClient(ak, sk, url=url)
ak = "xxx"
sk = "xxx"
bc = new RangersClient(ak, sk)
// 海外和私有化需要指定url地址, 可以参考 “OpenAPI 概览”
url = '{使用非中国区或者Finder服务域名替换}'
bc = RangersClient(ak, sk, url=url)
var (
ak = "xxx"
sk = "xxx"
)
bc := dslcontent.NewRangersClient(ak, sk)
// 海外和私有化需要指定url地址, 可以参考 “OpenAPI 概览”
url = '{使用非中国区或者Finder服务域名替换}'
bc := dslcontent.NewRangersClientWithUrl(ak, sk, url)
ak = "xxx";
sk = "xxx";
$bc = new RangersClient($ak, $sk);
// 海外和私有化需要指定url地址, 可以参考 “OpenAPI 概览”
$url = '{使用非中国区或者Finder服务域名替换}'
$bc = new RangersClient($ak, $sk, $url);
这里以Java 为例,其他的语言的代码可以查看 OpenAPI SDK 里面提供的源码。
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
public class AuthUtils {
/**
*
* @param ak accessKey
* @param sk secretKey
* @param expirationSeconds 过期时间,单位秒
* @param method 方法,GET, POST, PUT
* @param uriPath 请求的path,非完整的url
* @param params 请求参数
* @param body 请求的json体
* @return
*/
public static String sign(String ak, String sk, int expirationSeconds, String method, String uriPath, Map<String, String> params, String body) {
String cm = canonicalMethod(method);
String cu = canonicalUrl(uriPath);
String cp = canonicalParam(params);
String cb = canonicalBody(body);
String text = cm + "\n" + cu + "\n" + cp + "\n" + cb;
return doSign(ak, sk, expirationSeconds, text);
}
private static String canonicalMethod(String method) {
return "HTTPMethod:" + method;
}
private static String canonicalUrl(String url) {
return "CanonicalURI:" + url;
}
private static String canonicalParam(Map<String, String> params) {
String res = "CanonicalQueryString:";
if (params == null || params.isEmpty()) {
return res;
}
for (String key : params.keySet()) {
res += formatKeyValue(key, params.get(key)) + "&";
}
return res.substring(0, res.length() - 1);
}
private static String formatKeyValue(String key, String value) {
return key + "=" + value;
}
private static String canonicalBody(String body) {
String res = "CanonicalBody:";
if (body == null) {
return res;
} else {
return res + body;
}
}
private static String doSign(String ak, String sk, int expiration, String text) {
String signKeyInfo = "ak-v1/" + ak + "/" + (int) (System.currentTimeMillis() / 1000) + "/" + expiration;
String signKey = sha256Hmac(signKeyInfo, sk);
String signResult = sha256Hmac(text, signKey);
return signKeyInfo + "/" + signResult;
}
private static String sha256Hmac(String message, String secret) {
String hash = "";
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
hash = byteArrayToHexString(bytes);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return hash;
}
private static String byteArrayToHexString(byte[] b) {
StringBuilder hs = new StringBuilder();
String stmp;
for (int n = 0; b != null && n < b.length; n++) {
stmp = Integer.toHexString(b[n] & 0XFF);
if (stmp.length() == 1) {
hs.append('0');
}
hs.append(stmp);
}
return hs.toString().toLowerCase();
}
}
import java.util.LinkedHashMap;
import java.util.Map;
public class AuthGenDemo {
//分配的accessKey和secretKey
private static String accessKey = "****";
private static String secretKey = "****";
// 单位秒
private static Integer expirationSeconds = 300;
public static void main(String[] args) {
String method = "POST";
// 请求的path,非完整的url
String uri = "/dataprofile/openapi/v1/751/users/185";
Map<String, String> exampleQueryParams = new LinkedHashMap<>();
exampleQueryParams.put("set_once", "true");
String exampleQueryBodyJson = "{\"name\":\"name\",\"value\":\"zhangsan\"}";
String authorization = AuthUtils.sign(accessKey, secretKey, expirationSeconds,
method, uri, exampleQueryParams, exampleQueryBodyJson);
System.out.println("authorization: " + authorization);
}
}
此类报错错误通常是由于签名过期导致的。这种情况可能有以下几种原因:
可能原因 | 解决方案 |
---|---|
时间不同步。 | 确保两台机器的系统时间是同步的,可以使用NTP(网络时间协议)进行时间同步。 |
签名有效期过短。 | 检查签名生成时设置的有效期参数,确保其足够长。 |
请求延迟。 | 可以尝试增加签名的有效期。 |
签名生成错误。 | 检查签名生成的代码逻辑,确保其正确无误。 |