为保证API的安全使用,在调用API时阿里云会对每个API请求通过签名(Signature)进行身份验证。无论使用HTTP还是HTTPS协议提交请求,都需要在请求中包含签名信息。本文介绍计算签名的方法和示例。
步骤一:构造规范化请求字符串 排序参数。按照参数首字母的字典顺序对参数排序,排序参数包括公共请求参数和接口自定义参数,不包括公共请求参数中的Signature参数。 公共请求参数详情,请参见公共请求参数。 说明 当使用GET方法提交请求时,这些参数就是URL请求中的参数部分,即URL中?之后由&连接的部分。 编码参数。使用UTF-8字符集按照RFC3986规则编码请求参数和参数取值,编码规则如下: 字符A~Z、a~z、0~9以及字符-、_、.、~不编码。 其它字符编码成%XY的格式,其中XY是字符对应ASCII码的16进制。示例:半角双引号(")对应%22。 扩展的UTF-8字符,编码成%XY%ZA…的格式。 空格编码成%20,而不是加号(+)。 该编码方式与application/x-www-form-urlencodedMIME格式编码算法相似,但又有所不同。
如果您使用的是Java标准库中的java.net.URLEncoder,可以先用标准库中的percentEncode编码,然后将已编码字符中的加号(+)替换为%20、星号(*)替换为%2A、%7E替换为波浪号(~),即可得到上述规则描述的编码字符串。
private static final String ENCODING = "UTF-8"; private static String percentEncode(String value) throws UnsupportedEncodingException { return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null; } 使用等号(=)连接编码后的请求参数和参数取值。 使用与号(&)连接编码后的请求参数,注意参数排序与第1步一致。 现在,您得到了规范化请求字符串(CanonicalizedQueryString),其结构遵循请求结构。
步骤二:构造签名字符串 构造待签名字符串StringToSign。您可以同样使用percentEncode处理上一步构造出的规范化请求字符串,规则如下: StringToSign= HTTPMethod + "&" + //HTTPMethod:发送请求的 HTTP 方法,例如 GET。 percentEncode("/") + "&" + //percentEncode("/"):字符(/)UTF-8 编码得到的值,即 %2F。 percentEncode(CanonicalizedQueryString) //您的规范化请求字符串。 按照RFC2104的定义,计算待签名字符串StringToSign的HMAC-SHA1值。本示例使用的是Java Base64编码方法。 Signature = Base64( HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) ) ) 说明 计算签名时,RFC2104规定的Key值是您的AccessKeySecret并加上与号(&),其ASCII值为38。更多详情,请参见创建AccessKey。 将RFC3986规则编码后的参数Signature添加到规范化请求字符串URL中。 示例一:参数拼接法 本示例以调用DescribeDedicatedHosts查询一台或多台专有宿主机的详细信息为例。假设您获得了AccessKeyID=testid以及AccessKeySecret=testsecret,签名流程如下: 构造规范化请求字符串。 http://ecs.aliyuncs.com/?Timestamp=2016-02-23T12%3A46%3A24Z&Format=XML&AccessKeyId=testid&Action=DescribeDedicatedHosts&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-xxxx-xxxx-xxxx-xxxxxxxxxx&Version=2014-05-26&SignatureVersion=1.0 构造待签名字符串StringToSign。 GET&%2F&AccessKeyId%3Dtestid%26Action%3DDescribeDedicatedHosts%26Format%3DXML%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D3ee8c1b8-xxxx-xxxx-xxxx-xxxxxxxxx%26SignatureVersion%3D1.0%26Timestamp%3D2016-02-23T12%253A46%253A24Z%26Version%3D2014-05-26 计算签名值。因为AccessKeySecret=testsecret,用于计算的Key为testsecret&,计算得到的签名值为OLeaidS1JvxuMvnyHOwuJ+uX5qY=。本示例使用的是JavaBase64编码方法。 Signature = Base64( HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) ) ) 添加RFC3986规则编码后的Signature=OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3D到第1步的URL中。 http://ecs.aliyuncs.com/?SignatureVersion=1.0&Action=DescribeDedicatedHosts&Format=XML&SignatureNonce=3ee8c1b8-xxxx-xxxx-xxxx-xxxxxxxxx&Version=2014-05-26&AccessKeyId=testid&Signature=OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3D&SignatureMethod=HMAC-SHA1&Timestamp=2016-02-23T12%253A46%253A24Z 通过第4步得到的URL,您可以使用浏览器、curl或者wget等工具发起HTTP请求调用DescribeDedicatedHosts,查询一台或多台专有宿主机的详细信息。
示例二:编程语言法 本示例以调用DescribeDedicatedHosts为例。假设您获得了AccessKeyID=testid以及AccessKeySecret=testsecret,并且假定所有请求参数放在一个JavaMap<String, String>对象里。
预定义编码方法。 private static final String ENCODING = "UTF-8"; private static String percentEncode(String value) throws UnsupportedEncodingException { return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null; } 预定义编码时间格式Timestamp。参数Timestamp必须符合ISO8601规范,并需要使用UTC时间,时区为+0。 private static final String ISO8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; private static String formatIso8601Date(Date date) { SimpleDateFormat df = new SimpleDateFormat(ISO8601_DATE_FORMAT); df.setTimeZone(new SimpleTimeZone(0, "GMT")); return df.format(date); } 构造请求字符串。 final String HTTP_METHOD = "GET"; Map parameters = new HashMap(); // 输入请求参数 parameters.put("Action", "DescribeDedicatedHosts"); parameters.put("Version", "2014-05-26"); parameters.put("AccessKeyId", "testid"); parameters.put("Timestamp", formatIso8601Date(new Date())); parameters.put("SignatureMethod", "HMAC-SHA1"); parameters.put("SignatureVersion", "1.0"); parameters.put("SignatureNonce", UUID.randomUUID().toString()); parameters.put("Format", "XML"); // 排序请求参数 String[] sortedKeys = parameters.keySet().toArray(new String[]{}); Arrays.sort(sortedKeys); final String SEPARATOR = "&"; // 构造 stringToSign 字符串 StringBuilder stringToSign = new StringBuilder(); stringToSign.append(HTTP_METHOD).append(SEPARATOR); stringToSign.append(percentEncode("/")).append(SEPARATOR); StringBuilder canonicalizedQueryString = new StringBuilder(); for(String key : sortedKeys) { // 这里注意编码 key 和 value canonicalizedQueryString.append("&") .append(percentEncode(key)).append("=") .append(percentEncode(parameters.get(key))); } // 这里注意编码 canonicalizedQueryString stringToSign.append(percentEncode( canonicalizedQueryString.toString().substring(1))); 签名。因为AccessKeySecret=testsecret,所以用于计算HMAC的Key为testsecret&,计算得到的签名值为OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3D。 // 以下是一段计算签名的示例代码 final String ALGORITHM = "HmacSHA1"; final String ENCODING = "UTF-8"; key = "testsecret&"; Mac mac = Mac.getInstance(ALGORITHM); mac.init(new SecretKeySpec(key.getBytes(ENCODING), ALGORITHM)); byte[] signData = mac.doFinal(stringToSign.getBytes(ENCODING)); String signature = new String(Base64.encodeBase64(signData)); 增加签名参数后,按照RFC3986规则编码后的URL如下: http://ecs.aliyuncs.com/?SignatureVersion=1.0&Action=DescribeDedicatedHosts&Format=XML&SignatureNonce=3ee8c1b8-xxxx-xxxx-xxxxx-xxxxx&Version=2014-05-26&AccessKeyId=testid&Signature=OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3D&SignatureMethod=HMAC-SHA1&Timestamp=2016-02-23T12%253A46%253A24Z 使用浏览器、curl或者wget等工具发送HTTP请求。 返回结果默认为XML格式,如下所示。提交请求时,若指定参数Format=JSON,则返回结果为JSON格式。更多详情,请参见返回结果。 1 dh-2xxxxxxxxxxxxx PostPaid ecs.se1ne 32 cn-beijing-c 2018-08-13T07:59Z 2 Available ddh.se1ne cn-beijing myDDH 56 448.0 56 0 0 448.0 d7xxxxxxxxxxxxxxxxxdb 2999-09-08T16:00Z dh-2xxxxxxxxxxxxx PostPaid ecs.se1ne 32 cn-beijing-c 2018-08-13T07:59Z 2 Available ddh.se1ne cn-beijing myDDH 56 448.0 56 0 0 448.0 fxxxxxxxxxxxxxxx6ca6 2999-09-08T16:00Z 2 10 C9E9EA51-6B74-409E-BA40-107126A200D4
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。