對於每一次HTTP或者HTTPS協議請求,我們會根據訪問中的簽名資訊驗證訪問要求者身份。具體由使用AccessKeyID和AccessKeySecret對稱式加密驗證實現。
AccessKey相當於使用者密碼,AccessKey用於調用API,而使用者密碼用於登入 ECS控制台 。其中AccessKeyID是訪問者身份,AccessKeySecret是加密簽名字元串和伺服器端驗證簽名字元串的密鑰,必須嚴格保密謹防泄露。
说明 | |
我們提供了多種程式設計語言的SDK及第三方SDK,可以免去您簽名的煩惱。更多詳情,請下載 SDK。 |
步驟 1. 構造正常化請求字元串
- 排序參數。定序以首字母順序排序,排序參數包括 公共請求參數 和介面自訂參數,不包括公共請求參數中的
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-urlencoded
MIME格式編碼演算法相似,但又有所不同。如果您使用的是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),其結構遵循 請求結構。
步驟 2. 建構簽章字元串
- 構造待簽名字元串
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。 - 添加根據 RFC3986 規則編碼後的參數
Signature
到正常化請求字元串URL中。
樣本 1. 參數拼接法
以調用 DescribeRegions 查詢地域為例。假設您獲得了AccessKeyID=testid
以及AccessKeySecret=testsecret
,簽名流程如下所示:
- 構造正常化請求字元串。
http://ecs.aliyuncs.com/?Timestamp=2016-02-23T12:46:24Z&Format=XML&AccessKeyId=testid&Action=DescribeRegions&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&SignatureVersion=1.0
- 構造待簽名字元串
StringToSign
。GET&%2F&AccessKeyId%3Dtestid%26Action%3DDescribeRegions%26Format%3DXML%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf%26SignatureVersion%3D1.0%26Timestamp%3D2016-02-23T12%253A46%253A24Z%26Version%3D2014-05-26
- 計算簽名值。因為
AccessKeySecret=testsecret
,用於計算的Key為testsecret&
,計算得到的簽名值為OLeaidS1JvxuMvnyHOwuJ+uX5qY=
。樣本使用的是Java Base64編碼方法。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=DescribeRegions&Format=XML&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&AccessKeyId=testid&Signature=OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3D&SignatureMethod=HMAC-SHA1&Timestamp=2016-02-23T12%253A46%253A24Z
通過以上URL,您可以使用瀏覽器、curl或者wget等工具發起HTTP請求調用DescribeRegions
,查看阿里雲的地域列表。
樣本 2. 程式設計語言法
依然以調用 DescribeRegions 查詢地域為例。假設您獲得了AccessKeyID=testid以及AccessKeySecret=testsecret,並且假定所有請求參數放在一個Java Map<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", "DescribeRegions"); 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=DescribeRegions&Format=XML&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&AccessKeyId=testid&Signature=OLeaidS1JvxuMvnyHOwuJ%2BuX5qY%3D&SignatureMethod=HMAC-SHA1&Timestamp=2016-02-23T12%253A46%253A24Z
- 使用瀏覽器、curl或者wget等工具發送HTTP請求。
<DescribeRegionsResponse> <Regions> <Region> <LocalName>青島節點</LocalName> <RegionId>cn-qingdao</RegionId> </Region> <Region> <LocalName>杭州節點</LocalName> <RegionId>cn-hangzhou</RegionId> </Region> </Regions> <RequestId>833C6B2C-E309-45D4-A5C3-03A7A7A48ACF</RequestId> </DescribeRegionsResponse>
返回結果列舉了地域和地域ID列表。如果您在提交請求時,指定參數Format=JSON
,那麼返回結果的格式為JSON格式而不是XML格式。更多詳情,請參閱 返回結果。