O Direct Mail autentica cada solicitação de API com uma assinatura HMAC-SHA1 derivada do seu par de AccessKey.
Nota:
Ignore este tópico se você utiliza um SDK do Alibaba Cloud (disponível para Java, PHP e C#).
A API aceita solicitações GET e POST, mas o StringToSign difere entre elas.
Toda solicitação deve incluir uma assinatura, seja por HTTP ou HTTPS. O Direct Mail usa um AccessKey ID e um AccessKey secret para verificar o remetente. Gerencie seus pares de AccessKey no console User Information Management. O AccessKey ID identifica o solicitante; o AccessKey secret assina a solicitação e permite a verificação no servidor. Mantenha seu AccessKey secret em sigilo.
Etapas da assinatura
Para assinar uma solicitação:
-
Crie uma string de consulta canônica a partir dos parâmetros da solicitação.
a. Ordene os parâmetros.
Organize todos os parâmetros da solicitação (comuns e específicos da API) em ordem alfabética pelo nome. Exclua o parâmetro Signature.
Nota: Em solicitações GET, esses parâmetros correspondem à parte da URL da solicitação após o caractere
?e separados por&.b. Codifique cada nome e valor de parâmetro.
Codifique nomes e valores em URL usando UTF-8. Regras:
Não codifique A-Z, a-z, 0-9,
-,_,.ou~.Codifique outros caracteres como
%XY, ondeXYé o valor ASCII hexadecimal. Exemplo:"→%22.Codifique caracteres UTF-8 multibyte como
%XY%ZA….Codifique espaços como
%20, não como+.
Importante: Bibliotecas padrão de codificação URL (como
java.net.URLEncoder) seguem as regras deapplication/x-www-form-urlencoded. Após a codificação, substitua+por%20,*por%2Ae%7Epor~.c. Una cada nome e valor codificados com
=.d. Concatene todos os pares nome-valor com
&seguindo a ordem definida na etapa a. Isso gera a string de consulta canônica. -
Crie a string a ser assinada no seguinte formato:
StringToSign= HTTPMethod + "&" + percentEncode("/") + "&" + percentEncode(CanonicalizedQueryString)HTTPMethod é o método HTTP (GET ou POST).
percentEncode("/") codifica
/conforme as regras da etapa 1.b, resultando em%2F.percentEncode(CanonicalizedQueryString) codifica a string de consulta canônica da etapa 1 segundo as regras da etapa 1.b. Nota: Isso produz um resultado com codificação dupla.
-
Calcule o valor HMAC.
Calcule o HMAC-SHA1 do StringToSign conforme definido na RFC2104.
Nota: A chave de assinatura é o seu AccessKeySecret seguido por
&(ASCII 38). O algoritmo de hash é SHA1. -
Calcule o valor da assinatura.
Codifique o valor HMAC da etapa 3 em Base64. O resultado é a assinatura.
-
Adicione a assinatura à solicitação como o parâmetro Signature.
Nota: O valor de Signature deve ter codificação URL assim como os demais parâmetros, conforme a RFC3986.
Exemplo de assinatura
Este exemplo assina uma solicitação POST SingleSendMail.
URL da solicitação: http://dm.aliyuncs.com/
Parâmetros da solicitação:
AccessKeyId=testid&AccountName=<a%b'>&Action=SingleSendMail&AddressType=1&Format=XML&HtmlBody=4&RegionId=cn-hangzhou&ReplyToAddress=true&SignatureMethod=HMAC-SHA1&SignatureNonce=c1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c&SignatureVersion=1.0&Subject=3&TagName=2&Timestamp=2016-10-20T06:27:56Z&ToAddress=1@test.com&Version=2015-11-23
StringToSign:
POST&%2F&AccessKeyId%3Dtestid%26AccountName%3D%253Ca%2525b%2527%253E%26Action%3DSingleSendMail%26AddressType%3D1%26Format%3DXML%26HtmlBody%3D4%26RegionId%3Dcn-hangzhou%26ReplyToAddress%3Dtrue%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3Dc1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c%26SignatureVersion%3D1.0%26Subject%3D3%26TagName%3D2%26Timestamp%3D2016-10-20T06%253A27%253A56Z%26ToAddress%3D1%2540test.com%26Version%3D2015-11-23
Com AccessKeyId testid e AccessKeySecret testsecret, a chave de assinatura é testsecret&. A assinatura resultante:
llJfXJjBW3OacrVgxxsITgYaYm0=
Corpo POST assinado (com Signature adicionado e Content-Type definido como application/x-www-form-urlencoded):
Signature=llJfXJjBW3OacrVgxxsITgYaYm0=&AccessKeyId=testid&AccountName=<a%b'>&Action=SingleSendMail&AddressType=1&Format=XML&HtmlBody=4&RegionId=cn-hangzhou&ReplyToAddress=true&SignatureMethod=HMAC-SHA1&SignatureNonce=c1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c&SignatureVersion=1.0&Subject=3&TagName=2&Timestamp=2016-10-20T06:27:56Z&ToAddress=1@test.com&Version=2015-11-23
Codifique esses parâmetros em URL antes do envio..
Exemplos de código
Java
private static final String MAC_NAME ="HmacSHA1";
private static final String ENCODING ="UTF-8";
/**
* Signs encryptText using the HMAC-SHA1 method.
*
*@param encryptText The string to be signed.
*@param encryptKey The key.
*@return
*@throws Exception
*/
public static byte[] HmacSHA1Encrypt(StringencryptText, String encryptKey) throwsException {
byte[] data = encryptKey.getBytes(ENCODING);
// Creates a key from the given byte array. The second parameter specifies the name of the key algorithm.
SecretKey secretKey = new SecretKeySpec(data,MAC_NAME);
// Generates a Mac object for the specified Mac algorithm.
Mac mac = Mac.getInstance(MAC_NAME);
// Initializes the Mac object with the given key.
mac.init(secretKey);
byte[] text = encryptText.getBytes(ENCODING);
// Completes the Mac operation.
return mac.doFinal(text);
}
@Test
public void test() throws Exception {
/*StringToSign=
HTTPMethod + “&” +
percentEncode(“/”) + ”&” +
percentEncode(CanonicalizedQueryString)*/
String str ="AccessKeyId=testid&AccountName=<a%b'>&Action=SingleSendMail&AddressType=1&Format=XML&HtmlBody=4&RegionId=cn-hangzhou&ReplyToAddress=true&SignatureMethod=HMAC"+
"-SHA1&SignatureNonce=c1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c&SignatureVersion=1.0&Subject=3&TagName=2&Timestamp=2016-10-20T06:27:56Z&ToAddress=1@test.com&Version=2015-11-23";
String percentStr = "";
String[] strs = str.split("&");
for (int i = 0; i < strs.length;i++) {
String[] str1 =strs[i].split("=");
if (str1.length == 1){
percentStr = percentStr + getUtf8Encoder(str1[0])+ "=" + getUtf8Encoder("")+ "&";
}else {
percentStr = percentStr + getUtf8Encoder(str1[0])+ "=" + getUtf8Encoder(str1[1]) + "&";
}
}
percentStr =percentStr.substring(0,percentStr.lastIndexOf("&"));
String percent = URLEncoder.encode("/","UTF-8");
percentStr = getUtf8Encoder(percentStr);
String toSign = HttpMethod.POST + "&"+ percent +"&" + percentStr;
System.out.println("--------------"+ toSign);
/*POST&%2F&AccessKeyId%3Dtestid%26AccountName%3D%253Ca%2525b%2527%253E%26Action%3DSingleSendMail%26AddressType%3D1%26Format%3DXML%26HtmlBody%3D4%26RegionId%3Dcn-hangzhou%26ReplyToAddress%3Dtrue%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3Dc1b2c332-4cfb-4a0f-b8cc-ebe622aa0a5c%26SignatureVersion%3D1.0%26Subject%3D3%26TagName%3D2%26Timestamp%3D2016-10-20T06%253A27%253A56Z%26ToAddress%3D1%2540test.com%26Version%3D2015-11-23*/
byte[] bytes = HmacSHA1Encrypt(toSign,"testsecret&");
String base64Str = Base64.encode(bytes);
System.out.println(base64Str);//llJfXJjBW3OacrVgxxsITgYaYm0=
}
private String getUtf8Encoder(String param) throwsUnsupportedEncodingException {
return URLEncoder.encode(param, "UTF-8")
.replaceAll("\\+","%20")
.replaceAll("\\*","%2A")
.replaceAll("%7E","~");
};
Python
import hmac
import base64
# Replace StringToSign with the actual content.
message = b'StringToSign'
key = b'testsecret&'
h = hmac.new(key, message, digestmod='sha1')
# print(h.digest())
print(base64.b64encode(h.digest()))
PHP
<?php
function encryptTokey($data){
$apikey = 'testsecret&';
$sign = base64_encode(hash_hmac("sha1", $data, $apikey, true));
//printf($sign);
return $sign;
}
// Replace StringToSign with the actual content.
echo encryptTokey(StringToSign);
?>
Perguntas frequentes
Erros intermitentes de
SignatureDoesNotMatchgeralmente indicam que caracteres especiais não foram substituídos após a codificação. Consulte a nota Importante acima.Se houver problemas de incompatibilidade de assinatura não resolvidos, use o Exemplo de solicitação e substitua pelos seus próprios parâmetros.