You need to enable JavaScript to run this app.
导航

OpenAPI 认证鉴权

最近更新时间2023.10.31 15:40:29

首次发布时间2022.05.05 19:50:14

OpenAPI 使用 AK/SK 认证鉴权。

1. 获取AK/SK
  • SAAS上,可以联系您的客户成功经理或者火山客户经理获取AK/SK,也可以通过服务对接的飞书/微信群或页面右下角的在线客服与我们取得联系,收到请务必妥善保管和使用。

  • 私有化环境里面,在右上角“集团项目概览”(如图所示)中创建或者重置ak/sk。
    alt

说明

AK是平台为每个集团默认创建的;SK全局唯一,自行输入(长度 6~64个字符),请获取后妥善保管。

2. 签名说明

AK/SK认证就是使用AK/SK对请求进行签名,在请求时将签名信息添加到消息头,从而通过身份认证。

  • AK(Access Key ID):访问密钥ID。与私有访问密钥关联的唯一标识符;访问密钥ID和私有访问密钥一起使用,对请求进行加密签名。
  • SK(Secret Access Key):与访问密钥ID结合使用的密钥,对请求进行加密签名,可标识发送方,并防止请求被修改。

请求发送方使用方式如下:

  1. 以 “ak-v1/access_key/timestamp/expiretime"为认证字符串前缀。

    • ak-v1为版本号,用来表示一个认证字符串。

    • timestamp为代表签名生效UTC时间。

    • expiretime为签名有效期限。

  2. 使用签名算法(HmacSHA256),以认证字符串前缀为消息,secret_key为密钥,生成字符串sign_key。

  3. 把需要加密的字段放入canonicalRequest,其格式为:

    CanonicalRequest =
        HTTPMethod:${method} + '\n' +
        CanonicalURI:${uri} + '\n' +
        CanonicalQueryString:${queryString} + '\n' +
        CanonicalBody:${body}
    

    使用签名算法(HmacSHA256),以canonicalRequest为消息,sign_key为密钥,生成字符串signature。

  4. 最终的认证字符串为 “ak-v1/access_key/timestamp/expiretime/signature”。

  5. 把认证字符串放在http的header:Authorization:ak-v1/access_key/timestamp/expiretime/signature

3. 示例代码

这里以Java 为例,其他的语言的代码可以查看 OpenAPI SDK 里面提供的源码。

  • 签名 (AuthUtil.java)

    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);
        }
    }