认证方式使用

简单身份认证

客户端程序将AppCode和AppKey拼接后放到Request Header中,或者放到Request的Query参数中,从而进行身份认证。

参数名称

说明

示例值

Date

GMT格式的日期格式

Fri, 18 Jun 2021 07:14:23 GMT

Authorization

调用方的<AppCode><空格><AppKey>

productcode 3FQoSpxUbCgz5bCss

说明

简单身份认证模式下无需额外计算,直接使用上文获取的应用相关信息便可发起请求。

​加密身份认证

客户端程序需要使用AppKey和AppSecret,对一系列需要签名所需要的信息进行哈希运算,得到签名结果(一串字符串)。在调用API时,Request Header增加签名结果和密钥的内容,从而进行身份认证。

加密计算过程较为复杂,建议您优先使用产品提供的SDK及代码示例开始调用。

参数名称

说明

示例值

Date

GMT格式的日期格式

Fri, 18 Jun 2021 07:14:23 GMT

signature

计算得到签名

productcode 3FQoSpxUbCgz5bCss:BwLDKVZxb6Ig7T6PdEibkWfkftFQ=

计算说明

1)Content计算:
    # GET请求
    ${method}\n${path}\n${date}
    # 非GET请求
    ${method}\n${path}\n${date}\n${bodyMd5}

2)SignStr计算:
		对步骤1)得到的Content内容,以AppSecret为密钥做HmacSHA1加密后,对密文做base64编码输出

3)signature计算:
		signature = AppCode<空格>AppKey:SignStr
说明

path中如果包含特殊字符需要做Encode。

使用示例

1. Java应用-SDK调用(推荐)

Dbus已经将加密身份认证模式所需的签名的计算方法封装在SDK中,以供调用方的Java应用集成,引入SDK后可以直接通过SDK中的方法发起调用请求,无需再手动计算认证签名,方便快捷。

1)在应用中通过Maven添加如下依赖:

<dependency>
  <groupId>com.aliyun.dataq.service.dbus</groupId>
  <artifactId>dbus-sdk</artifactId>
  <version>1.0.3-SNAPSHOT</version>
</dependency>

​2) 手动下载SDK后在本地引入依赖

下载链接:SDK下载

安装至本地仓库:

  mvn install:install-file\
    -DgroupId=com.aliyun.dataq.service.dbus\
    -DartifactId=dbus-sdk\
    -Dversion=1.0.3-SNAPSHOT\
    -Dpackaging=jar\
    -Dfile=${安装包所在的本机路径}/dbus-sdk-1.0.3-SNAPSHOT-jar-with-dependencies.jar

SDK调用示例代码:

public static void main(String[] args) {
    //目标API的地址
    String endpoint = "https://dataq.aliyuncs.com";
    //目标API的路径
    String path = "/yourworkspaceCode/yourAppCode/APIPath";
    //已获得调用授权或者自有API创建时选择的应用Code、AppKey及AppSecret
    String appCode = "yourAppCode";
    String appKey = "yourAppKey";
    String appSecret = "yourAppSecret";

    DataQService.Builder builder = new DataQService.Builder();
    builder.setPath(path);
    builder.setAppKey(appKey);
    builder.setAppSecret(appSecret);
    builder.setModuleName(appCode);

    //添加请求Header参数
    Map<String, Object> headerMap = new HashMap<>();
    headerMap.put("Accept", "application/json");
    headerMap.put("Content-Type", "application/json");
    headerMap.put("h1", "");
    headerMap.put("h2", "");
    builder.addHeader(headerMap);

    //添加QueryParam参数
    Map<String, Object> queryParam = new HashMap<>();
    queryParam.put("p1", "");
    queryParam.put("p2", "");
    builder.addQueryParam(queryParam);

    //添加RequestBody参数
    Map<String, Object> map = new HashMap<>();
    map.put("b1", "");
    List<String> values = Arrays.asList("v1");
    map.put("b2", values);
    builder.setRequestBody(new JSONObject(map));

    //文件上传
    MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
            .addTextBody("k1","v1")
            .addTextBody("k2","v2")
            .addBinaryBody("file", new File("/demo/2602780.txt"),  ContentType.APPLICATION_OCTET_STREAM, "2602780.txt");
    builder.setMultipartEntityBuilder(multipartEntityBuilder);

    //设置请求方法
    DataQService dataQService = builder.setHttpMethod(HttpMethod.GET).build();

    //初始化请求客户端
    DaasClient client = new DaasClient(endpoint);

    //发送请求
    Object httpResponse = client.invoke(dataQService, 1000000, 30);
	
	  //返回结果
    System.out.println(httpResponse);
}

b. Java应用-自行计算签名

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public abstract class SignUtils {

    public static final String EMPTY_STRING_MD5;

    private static FastDateFormat DATE_FORMAT;

    static {
        DATE_FORMAT = FastDateFormat
                .getInstance("E, dd MMM yyyy HH:mm:ss z", TimeZone.getTimeZone("GMT"), Locale.UK);
        try {
            MessageDigest md = MessageDigest.getInstance("md5");
            md.update("".getBytes("UTF-8"));
            EMPTY_STRING_MD5 = Base64.encodeBase64String(md.digest());
        } catch (Exception ex) {
            throw new IllegalArgumentException(ex);
        }
    }

    public static Date parseGmtDate(String date) throws ParseException {
        return DATE_FORMAT.parse(date);
    }

    public static String formatGmtDate(Date date) {
        return DATE_FORMAT.format(date);
    }

    public static String toMd5(InputStream stream) throws Exception {
        return toMd5(stream, false);
    }

    public static String toMd5(InputStream stream, boolean parseEmptyStream) throws Exception {
        try {
            boolean nocontent = true;
            MessageDigest md = MessageDigest.getInstance("md5");

            int len = -1;
            byte[] buf = new byte[1024];

            while ((len = stream.read(buf)) != -1) {
                nocontent = false;
                md.update(buf, 0, len);
            }

            return nocontent ?
                    (parseEmptyStream ? EMPTY_STRING_MD5 : "") :
                    Base64.encodeBase64String(md.digest());
        } finally {
            stream.close();
        }
    }

    public static String toMd5(byte[] content) throws Exception {
        if (content == null || content.length == 0) {
            return null;
        }
        return Base64.encodeBase64String(MessageDigest.getInstance("md5").digest(content));
    }

    public static String toMd5(String content) throws Exception {
        return toMd5(content.getBytes("UTF-8"));
    }

    public static String toHmacSHA1(String data, String AppSecret) throws Exception {
        String algorithm = "HmacSHA1";
        SecretKeySpec signingKey = new SecretKeySpec(AppSecret.getBytes("UTF-8"), algorithm);
        Mac mac = Mac.getInstance(algorithm);
        mac.init(signingKey);
        byte[] rawHmac = mac.doFinal(data.getBytes("UTF-8"));
        return Base64.encodeBase64String(rawHmac);
    }

    public static String sign4Base(String param, String salt) throws Exception {
        if (StringUtils.isEmpty(param) || StringUtils.isEmpty(salt)) {
            return null;
        }

        String query = URLDecoder.decode(param, "UTF-8");

        String[] pStr = query.trim().split("&");
        Arrays.sort(pStr);

        StringBuilder buf = new StringBuilder(salt).append(':');
        for (int i = 0; i < pStr.length; ++i) {
            buf.append(pStr[i]);
            buf.append("&");
        }
        buf.setCharAt(buf.length() - 1, ':');
        buf.append(salt);

        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] bytes = md.digest(buf.toString().getBytes("UTF-8"));

        return Hex.encodeHexString(bytes).toLowerCase();
    }

    private static String signedString(String method, String url, String date, String contentMd5) {
        HttpMethod hm = HttpMethod.valueOf(method.toUpperCase());
        if (hm == null) {
            throw new IllegalArgumentException("Unknow Http Method: " + method);
        }

        if (hm.needBody && contentMd5 == null) {
            contentMd5 = "";
        }
        if (contentMd5 == null) {
            StringBuilder buf = new StringBuilder(method.length() + url.length() + date.length());
            return buf.append(method).append('\n').append(url).append('\n').append(date).toString();
        }
        StringBuilder buf = new StringBuilder(
                method.length() + url.length() + date.length() + contentMd5.length());
        return buf.append(method).append('\n').append(url).append('\n').append(date).append('\n')
                .append(contentMd5).toString();
    }

    private static String doSign(String module, String appKey, String appSecret, String signedString)
            throws Exception {
        String signature = toHmacSHA1(signedString, appSecret);
        StringBuilder buf = new StringBuilder(module.length() + accessId.length() + signature.length() + 2);
        return buf.append(module).append(' ').append(appKey).append(':').append(signature).toString();
    }

    public static String originalSign4Dtboost(String appSecret, String method, String url, String gmtDate)
            throws Exception {
        return originalSign4Dtboost(appSecret, method, url, gmtDate, null);
    }

    public static String originalSign4Dtboost(String appSecret, String method, String url, String gmtDate,
                                              String contentMd5) throws Exception {
        String signedString = signedString(method, url, gmtDate, contentMd5);
        return toHmacSHA1(signedString, appSecret);
    }

    public static String sign4Dtboost(String module, String appKey, String appSecret, String method,
                                      String url, String gmtDate) throws Exception {
        return sign4Dtboost(module, appKey, appSecret, method, url, gmtDate, null);
    }

    public static String sign4Dtboost(String module, String appKey, String appSecret, String method,
                                      String url, String gmtDate, String contentMd5) throws Exception {
        String signedString = signedString(method, url, gmtDate, contentMd5);
        return doSign(module, appKey, appSecret, signedString);
    }

    public static String[] spliteSign4Dtboost(String signature) {
        int moduleIndex = signature.indexOf(' ');
        if ((moduleIndex < 1) || (moduleIndex + 3) == signature.length()) {
            return null;
        }
        int accessIdIndex = signature.indexOf(':', moduleIndex);
        if ((accessIdIndex < 2) || (accessIdIndex + 1) == signature.length()) {
            return null;
        }
        return new String[] {signature.substring(0, moduleIndex),
                signature.substring(moduleIndex + 1, accessIdIndex), signature.substring(accessIdIndex + 1)};
    }

    private static String signedString(String method, String accept, String gmtDate, String url,
                                       String contentType, String contentMd5) {
        if (accept == null) {
            accept = "";
        }
        if (contentType == null) {
            contentType = "";
        }
        if (contentMd5 == null) {
            contentMd5 = "";
        }
        method = method.toUpperCase();

        StringBuilder buf = new StringBuilder(
                method.length() + accept.length() + gmtDate.length() + url.length() + contentType.length()
                        + contentMd5.length());

        return buf.append(method).append('\n').append(accept).append('\n').append(contentMd5).append('\n')
                .append(contentType).append('\n').append(gmtDate).append('\n').append(url).toString();
    }

    public static String originalSign4Dataplus(String appSecret, String method, String accept, String gmtDate,
                                               String url) throws Exception {
        return originalSign4Dataplus(appSecret, method, accept, gmtDate, url, null, null);
    }

    public static String originalSign4Dataplus(String appSecret, String method, String accept, String gmtDate,
                                               String url, String contentType, String contentMd5) throws Exception {
        String signedString = signedString(method, accept, gmtDate, url, contentType, contentMd5);
        return toHmacSHA1(signedString, appSecret);
    }

    @Deprecated public static String sign4Datapuls(String module, String appKey, String appSecret,
                                                   String method, String accept, String gmtDate, String url) throws Exception {
        return sign4Dataplus(module, appKey, appSecret, method, accept, gmtDate, url);
    }

    public static String sign4Dataplus(String module, String appKey, String appSecret, String method,
                                       String accept, String gmtDate, String url) throws Exception {
        return sign4Dataplus(module, appKey, appSecret, method, accept, gmtDate, url, null, null);
    }

    @Deprecated public static String sign4Datapuls(String module, String appKey, String appSecret,
                                                   String method, String accept, String gmtDate, String url, String contentType, String contentMd5)
            throws Exception {
        return sign4Datapuls(module, appKey, appSecret, method, accept, gmtDate, url, contentType,
                contentMd5);
    }

    public static String sign4Dataplus(String module, String appKey, String appSecret, String method,
                                       String accept, String gmtDate, String url, String contentType, String contentMd5)
            throws Exception {
        String signedString = signedString(method, accept, gmtDate, url, contentType, contentMd5);
        return doSign(module, appKey, appSecret, signedString);
    }

    public static String[] spliteSign4Dataplus(String signature) {
        return spliteSign4Dtboost(signature);
    }

    enum HttpMethod {
        /**
         * HTTP METHOD
         */
        GET(false), POST(true), PUT(true), DELETE(false), PATCH(true), HEAD(false), OPTIONS(false), TRACE(
                false);

        private final boolean needBody;

        private HttpMethod(boolean needBody) {
            this.needBody = needBody;
        }
    }

    public static final class Md5CalculatedOutputStream extends OutputStream {

        private boolean nocontent = true;

        private final MessageDigest md;
        private final boolean parseEmptyStream;

        public Md5CalculatedOutputStream() throws NoSuchAlgorithmException {
            this(false);
        }

        public Md5CalculatedOutputStream(boolean parseEmptyStream) throws NoSuchAlgorithmException {
            md = MessageDigest.getInstance("md5");
            this.parseEmptyStream = parseEmptyStream;
        }

        @Override public void write(int b) throws IOException {
            if (nocontent) {
                nocontent = false;
            }
            md.update((byte) b);
        }

        @Override public void write(byte b[]) throws IOException {
            if (b == null) {
                throw new NullPointerException();
            } else if (b.length != 0) {
                if (nocontent) {
                    nocontent = false;
                }
                md.update(b);
            }

        }

        @Override public void write(byte b[], int off, int len) throws IOException {
            if (b == null) {
                throw new NullPointerException();
            } else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len)
                    < 0)) {
                throw new IndexOutOfBoundsException();
            } else if (len != 0) {
                if (nocontent) {
                    nocontent = false;
                }
                md.update(b, off, len);
            }
        }

        public String toMd5() {
            if (nocontent) {
                return parseEmptyStream ? EMPTY_STRING_MD5 : "";
            }
            return Base64.encodeBase64String(md.digest());
        }
    }
}

c. JS应用-自行计算签名

function sign(url, method, headers, appKey, appSecret, body) {
      const appSecret = appSecret;
      const md5 = function (buffer) {
        return crypto.createHash('md5').update(buffer).digest('base64');
      };
      const sha1 = function (stringToSign, appSecret) {
        return crypto.createHmac('sha1', AppSecret).update(stringToSign).digest().toString('base64');
      };
      body = body || {};
      let bodymd5 = '';
      if (body && _.size(body) && ['POST', 'PUT', 'PATCH'].indexOf(method.toUpperCase()) >= 0) {
        bodymd5 = crypto.createHash('md5').update(Buffer.from(JSON.stringify(body))).digest('base64');
      }
      let stringToSign = method + '\n' + Url.parse(url).path + '\n' + headers.date;
      if (bodymd5) {
        stringToSign = stringToSign + '\n' + bodymd5;
      }
      let signature = sha1(stringToSign, appSecret);
      let authHeader = `common-user-ak-v1 ${appKey}:${signature}`;
      return authHeader;
  }