请求签名

请求签名方法

使用控制台创建密钥,获得 AccessKeyId 和 AccessKeySecret,这里我们做以下假设:

AccessKeyId=6792aa42d288422ab8dd4654dfe727c4
AccessKeySecret=2f59e0d79d36442a899b54136cd7dc82

下面以开通虚拟机的 API 为例子,说明一下,如何使用构造请求的签名 例如我们请求ch-wuxi1机房中的创建云主机操作:

https://api.chinac.com/?Action=RunInstance
&Region=cn-wuxi1
&ImageId=t-ej8hh1dex32l
&InstanceType=11核1G_SERIES_STANDARD
&FirewallId=f-g18hh7tffy34g
&Interface.0.NetworkId=noy8hh7i9na39w
&Volumes.0.Type=normal
&Volumes.0.Size=20
&Volumes.1.Type=normal
&Volumes.1.Size=20
&InstanceType=1%E6%A0%B81G_SERIES_STANDARD
&Period=1&PayType=PREPAID
&AccessKeyId=6792aa42d288422ab8dd4654dfe727c4
&Date=2017-09-13T15%3A40%3A19%20%2B0800
&Name=%E6%B5%8B%E8%AF%95%E6%8C%89%E9%87%8Fapi
&Version=1.0
&Signature=qx5mPbG0UvLSN4wKdnfmqcB63tmKi8qQUvq52ixAAAQ%3D

1.按照url请求参数的顺序(不限制顺序)进行URL编码(除Signature)

警告:编码时空格要转换成 “%20” , 而不是 “+”;"*"要转换成"%2A"

Name=%E6%B5%8B%E8%AF%95%E6%8C%89%E9%87%8Fapi&ImageId=t-ej8hh1dex32l&InstanceType=1%E6%A0%B81G_SERIES_STANDARD&FirewallId=f-g18hh7tffy34g&Interface.0.NetworkId=n-oy8hh7i9na39w&Volumes.0.Type=normal&Volumes.0.Size=20&Volumes.1.Type=normal&Volumes.1.Size=20&InstanceSeries=SERIES_STANDARD&Period=1&PayType=PREPAID&Region=cn-wuxi1&AccessKeyId=6792aa42d288422ab8dd4654dfe727c4&Date=2017-09-13T15%3A40%3A19%20%2B0800&Action=RunInstance&Version=1.0&Signature=qx5mPbG0UvLSN4wKdnfmqcB63tmKi8qQUvq52ixAAAQ%3D

假设URL编码后的字符串命名为$sbParams

2.将进行过编码的字符串进行MD5

MD5的php代码:

md5(http_build_query($sbParams, '', '&', PHP_QUERY_RFC3986)) . "\n";

3.生成要签名的字符串

生成签名的字符串格式: METHOD + "\n" + MD5(sbParams) + "\n" + ContentType + "\n" + 时间 + "\n"

说明:

  • HTTP请求方式 METHOD:GET 或 POST
  • ContentType 例如: application/json;charset=UTF-8
  • 时间 :2016-09-02T16%3A59%3A00%20%2B0800

生成例如:

aBRnnyo3MLKiJAfxDzEE9X4NvOn%2FZZ%2BBBzHG%2FJYPKjI%3D

假设生成的签名命名为 stringToSign

生成签名

生成签名规则:

  1. 使用最早获取的 AccessKeySecret 和 HMAC-SHA256 算法来生成签名,详细可以参考 RFC2104。
  2. 将以上得到的签名字符串stringToSign使用 Base64 编码。

签名的php代码:

//设置时区
date_default_timezone_set('PRC');

//所有请求参数,不包括签名
$parameters = ['Action'=>'RunInstance', 'Name'=>'云主机名称', 'Date'=>date('Y-m-d\TH:i:s O')];

//自己accessKeySecret
$accessKeySecret = 'accessKeySecret';

$signature = compute_signature($parameters, $accessKeySecret, 'GET');

function compute_signature($parameters, $accessKeySecret, $method = 'GET')
{
    $stringToSign = $method . "\n";
    $stringToSign .= md5(http_build_query($parameters, '', '&', PHP_QUERY_RFC3986)) . "\n";
    $stringToSign .= "application/json;charset=UTF-8\n";
    $stringToSign .= rawurlencode($parameters['Date']) . "\n";
    $signature = percent_encode(sign_string($stringToSign, $accessKeySecret));
    return $signature;
}

function sign_string($string, $accessKeySecret)
{
    return base64_encode(hash_hmac('sha256', $string, $accessKeySecret, true));
}

function percent_encode($str)
{
    $res = urlencode($str);
    $res = preg_replace('/\+/', '%20', $res);
    $res = preg_replace('/\*/', '%2A', $res);
    $res = preg_replace('/%7E/', '~', $res);
    return $res;
}

    

生成的签名字符串作为请求参数Signature

4.最终生成的请求URL如下:

https://api.chinac.com/?Action=RunInstance
&Region=cn-wuxi1
&ImageId=t-ej8hh1dex32l
&InstanceType=11核1G_SERIES_STANDARD
&FirewallId=f-g18hh7tffy34g
&Interface.0.NetworkId=noy8hh7i9na39w
&Volumes.0.Type=normal
&Volumes.0.Size=20
&Volumes.1.Type=normal
&Volumes.1.Size=20
&InstanceType=1%E6%A0%B81G_SERIES_STANDARD
&Period=1&PayType=PREPAID
&AccessKeyId=6792aa42d288422ab8dd4654dfe727c4
&Date=2017-09-13T15%3A40%3A19%20%2B0800
&Name=%E6%B5%8B%E8%AF%95%E6%8C%89%E9%87%8Fapi
&Version=1.0
&Signature=qx5mPbG0UvLSN4wKdnfmqcB63tmKi8qQUvq52ixAAAQ%3D