全部产品
存储与CDN 数据库 安全 应用服务 数加·人工智能 数加·大数据基础服务 互联网中间件 视频服务 开发者工具 解决方案 物联网
视频点播

API签名机制

更新时间:2017-10-16 14:28:19

阿里云产品服务会对每个访问请求进行身份验证,所以无论您使用 HTTP 还是 HTTPS 协议提交请求,都需要在请求中包含签名(Signature)信息。

签名需要您在控制台 Access Key 管理 页面获得 Access Key ID 和 Access Key Secret,进行对称加密来验证请求的发送者身份。其中,Access Key ID 用于标识访问者身份;Access Key Secret 是用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密。

注意:阿里云提供了 PythonJavaPHPC# 等语言的 SDK 及第三方 SDK,可以免去您对签名算法进行编码的麻烦。您可以从 这里 了解更多阿里云 SDK 的信息。

签名操作

您在访问时,需要按照下面的方法对请求进行签名处理。

  1. 构造规范化的请求字符串(CanonicalizedQueryString)

    i. 按参数名进行排序

    1. 按照参数名称的字典顺序对请求中所有的请求参数进行排序,包括“公共请求参数”(不包括 Signature 参数)和接口的自定义参数。

    注意:当使用 GET 方法提交请求时,这些参数就是请求 URI 中的参数部分(即 URI 中“?”之后由“&”连接的部分)。

    ii. 对参数名称和参数值进行 URL 编码

    名称和值要使用 UTF-8 字符集进行 URL 编码。URL 编码的规则如下:

    • 字符 A~Z、a~z、0~9 以及字符“-”、“_”、“.”、“~”不编码;
    • 其它字符编码成 %XY 的格式,其中 XY 是字符对应 ASCII 码的 16 进制表示。比如英文的双引号(”)对应的编码为 %22
    • 对于扩展的 UTF-8 字符,编码成 %XY%ZA… 的格式;
    • 英文空格( )要编码成 %20,而不是加号(+)。

      注意:一般支持URL编码的库(比如 Java 中的 java.net.URLEncoder)都是按照 “application/x-www-form-urlencoded”的 MIME 类型的规则进行编码的。实现时可以直接使用这类方式进行编码,把编码后的字符串中加号(+)替换成 %20、星号(*)替换成 %2A%7E 替换回波浪号(~),即可得到上述规则描述的编码字符串。

    iii. 对编码后的参数名称和值使用英文等号(=)进行连接

    iv. 按参数名称的字典顺序,把英文等号连接得到字符串依次使用 & 符号连接,即得到规范化请求字符串。

  2. 构造待签名字符串(StringToSign)

    基于步骤 1 得到的规范化字符串构造用于计算签名的字符串,可参考如下规则:

    1. StringToSign=
    2. HTTPMethod + “&” +
    3. percentEncode(“/”) + ”&” +
    4. percentEncode(CanonicalizedQueryString)

    其中:

    • HTTPMethod 是提交请求用的 HTTP 方法,比如 GET。
    • percentEncode(“/”) 是按照步骤 1.i 中描述的 URL 编码规则对字符 “/” 进行编码得到的值,即 %2F
    • percentEncode(CanonicalizedQueryString) 是对步骤 1 中构造的规范化请求字符串按步骤 1.ii 中描述的 URL 编码规则编码后得到的字符串。
  3. 计算 HMAC 值

    按照 RFC2104 的定义,使用步骤 2 得到的字符串计算签名 HMAC 值。

    注意:计算签名时使用的 Key 就是您持有的 Access Key Secret 并加上一个 “&” 字符(ASCII:38),使用的哈希算法是 SHA1。

  4. 计算签名值。

    按照 Base64 编码规则 把步骤 3 中的 HMAC 值编码成字符串,即得到签名值(Signature)。

  5. 添加签名。

    将得到的签名值作为 Signature 参数添加到请求参数中,即完成对请求签名的过程。

    注意:得到的签名值在作为最后的请求参数值提交给服务器时,要和其它参数一样,按照 RFC3986 的规则进行 URL 编码。

示例

以 GetVideoPlayAuth 为例,假设使用的 Access Key IdtestAccessKeyIdAccess Key SecrettestAccessKeySecret。 那么签名前的请求 URL 为:

  1. http://vod.cn-shanghai.aliyuncs.com/?TimeStamp=2017-10-10T12:02:54Z&Format=XML&AccessKeyId=testAccessKeyId&Action=GetVideoPlayAuth&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2017-03-21&SignatureVersion=1.0&VideoId=5aed81b74ba84920be578cdfe004af4b

计算得到的待签名字符串 StringToSign 为:

  1. GET&%2F&AccessKeyId%3DtestAccessKeyId&Action%3DGetVideoPlayAuth&Format%3DJSON&SignatureMethod%3DHMAC-SHA1&SignatureNonce%3D8f8a035d-6496-4268-afd4-67c22837e38d&SignatureVersion%3D1.0&Timestamp%3D2017-10-10T12%253A02%253A54Z&Version%3D2017-03-21&VideoId%3D5aed81b74ba84920be578cdfe004af4b

因为 Access Key SecrettestAccessKeySecret,所以用于计算 HMAC 的 Key 为 testAccessKeySecret&,计算得到的签名值为:

  1. Ibgh7y8Vp47LBuAsf5Xhi1SvDss%3D

将签名作为 Signature 参数加入到 URL 请求中,最后得到的 URL 为:

  1. http://vod.cn-shanghai.aliyuncs.com?AccessKeyId=testAccessKeyId&Action=GetVideoPlayAuth&Format=JSON&SignatureMethod=HMAC-SHA1&SignatureNonce=8f8a035d-6496-4268-afd4-67c22837e38d&SignatureVersion=1.0&Timestamp=2017-10-10T12%3A02%3A54Z&Version=2017-03-21&VideoId=5aed81b74ba84920be578cdfe004af4b&Signature=Ibgh7y8Vp47LBuAsf5Xhi1SvDss%3D

Java 示例代码

以下将为您介绍OpenAPI公共参数中需要您通过代码生成的参数,其他参数请根据文档填写具体值(本示例不需要依赖第三方的库包,可以直接使用)。

1. 生成Signature

构造签名字符串分为以下几个步骤进行:

1.1. 构造规范化的请求字符串(排序及URL编码)

  1. /*对所有参数名称和参数值做URL编码*/
  2. public static List<String> getAllParams(Map<String, String> publicParams, Map<String, String> privateParams) {
  3. List<String> encodeParams = new ArrayList<String>();
  4. if (publicParams != null) {
  5. for (String key : publicParams.keySet()) {
  6. String value = publicParams.get(key);
  7. //将参数和值都urlEncode一下。
  8. String encodeKey = percentEncode(key);
  9. String encodeVal = percentEncode(value);
  10. encodeParams.add(encodeKey + "=" + encodeVal);
  11. }
  12. }
  13. if (privateParams != null) {
  14. for (String key : privateParams.keySet()) {
  15. String value = privateParams.get(key);
  16. //将参数和值都urlEncode一下。
  17. String encodeKey = percentEncode(key);
  18. String encodeVal = percentEncode(value);
  19. encodeParams.add(encodeKey + "=" + encodeVal);
  20. }
  21. }
  22. return encodeParams;
  23. }
  24. /*获取 CanonicalizedQueryString*/
  25. public static String getCQS(List<String> allParams) {
  26. ParamsComparator paramsComparator = new ParamsComparator();
  27. Collections.sort(allParams, paramsComparator);
  28. String cqString = "";
  29. for (int i = 0; i < allParams.size(); i++) {
  30. cqString += allParams.get(i);
  31. if (i != allParams.size() - 1) {
  32. cqString += "&";
  33. }
  34. }
  35. return cqString;
  36. }
  37. /*字符串参数比较器*/
  38. public static class ParamsComparator implements Comparator<String> {
  39. @Override
  40. public int compare(String lhs, String rhs) {
  41. return lhs.compareTo(rhs);
  42. }
  43. }

1.2. 构造待签名的字符串

  1. /*构造待签名的字符串*/
  2. String StringToSign = httpMethod + "&" + percentEncode("/") + "&" + percentEncode(CanonicalizedQueryString);
  3. /*特殊字符替换为转义字符*/
  4. public static String percentEncode(String value) {
  5. try {
  6. String urlEncodeOrignStr = URLEncoder.encode(value, "UTF-8");
  7. String plusReplaced = urlEncodeOrignStr.replace("+", "%20");
  8. String starReplaced = plusReplaced.replace("*", "%2A");
  9. String waveReplaced = starReplaced.replace("%7E", "~");
  10. return waveReplaced;
  11. } catch (UnsupportedEncodingException e) {
  12. e.printStackTrace();
  13. }
  14. return value;
  15. }

1.3. 计算待签名字符串的HMAC值

  1. public static byte[] hmacSHA1Signature(String accessKeySecret, String stringToSign) {
  2. try {
  3. String key = accessKeySecret + "&";
  4. try {
  5. SecretKeySpec signKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
  6. Mac mac = Mac.getInstance("HmacSHA1");
  7. mac.init(signKey);
  8. return mac.doFinal(stringToSign.getBytes());
  9. } catch (Exception e) {
  10. throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
  11. }
  12. } catch (SignatureException e) {
  13. e.printStackTrace();
  14. }
  15. return null;
  16. }

1.4. 按照 Base64 编码规则将1.3中计算得到的HMAC值编码成字符串,得到最终签名值(Signature)

  1. public static String newStringByBase64(byte[] bytes)
  2. throws UnsupportedEncodingException {
  3. if (bytes == null || bytes.length == 0) {
  4. return null;
  5. }
  6. return new String(new BASE64Encoder().encode(bytes));
  7. }

2. 生成TimeStamp(UTC时间戳,如:2017-10-10T12:02:54Z)

  1. /*生成当前UTC时间戳Time*/
  2. public static String generateTimestamp() {
  3. Date date = new Date(System.currentTimeMillis());
  4. SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
  5. df.setTimeZone(new SimpleTimeZone(0, "GMT"));
  6. return df.format(date);
  7. }

3. 生成随机数SignatureNonce

  1. public static String generateRandom() {
  2. String signatureNonce = UUID.randomUUID().toString();
  3. return signatureNonce;
  4. }

至此,已经为您重点介绍了如何生成OpenAPI核心参数的代码示例,为了方便您快速使用签名机制,您可以在OpenAPI调用示例 下载完整的OpenAPI调用示例Java代码。

本文导读目录