OpenAPI 使用 AK/SK 认证鉴权。
说明
AK是平台为每个集团默认创建的;SK为每个用户唯一,不允许自行输入,请获取后妥善保管。
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
这里以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);
}
}