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
这里以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); } }