增长分析(即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(网络时间协议)进行时间同步。 |
签名有效期过短。 | 检查签名生成时设置的有效期参数,确保其足够长。 |
请求延迟。 | 可以尝试增加签名的有效期。 |
签名生成错误。 | 检查签名生成的代码逻辑,确保其正确无误。 |