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

OpenAPI 认证鉴权

最近更新时间2024.02.27 11:47:20

首次发布时间2024.02.27 11:47:20

OpenAPI 使用 AK/SK 认证鉴权。

1. 获取AK/SK
  • SAAS上,可以联系您的客户成功经理或者火山客户经理获取AK/SK,也可以通过服务对接的飞书/微信群或页面右下角的在线客服与我们取得联系,收到请务必妥善保管和使用。
  • 私有化环境里面,在右上角“集团项目概览”(如图所示)中创建或者重置ak/sk。
    图片

说明

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