记录下,阿里云的签名验证真心蛋疼,比如时间戳做了二次utf8转码,文档中的签名结果与实际不相符等
package AliYun;
use Moose;
use Redis;
use POSIX qw(strftime);
use Data::Dumper;
use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
use JSON;
use URI::Escape;
use LWP::UserAgent;
#定义签名常量
has 'accessKeyId' => ( isa => 'Str', is => 'ro', required => 1 );
has 'accessKeySecret' => ( isa => 'Str', is => 'ro', required => 1 );
has 'format' =>
( isa => 'Str', is => 'rw', required => 1, default => 'json' );
has 'signatureMethod' =>
( isa => 'Str', is => 'rw', required => 1, default => 'HMAC-SHA1' );
has 'signatureVersion' =>
( isa => 'Str', is => 'rw', required => 1, default => '1.0' );
has 'serverUrl' => ( isa => 'Str', is => 'rw', required => 1 );
has 'version' =>
( isa => 'Str', is => 'rw', required => 1, default => '2015-01-09' );
has 'requestMethod' =>
( isa => 'Str', is => 'rw', required => 1, default => 'GET' );
has 'timestamp' => (
isa => 'Str',
is => 'rw',
required => 1,
default => strftime( "%Y-%m-%dT%H:%M:%SZ", localtime( time - 3600 * 8 ) )
);
sub params_init {
my $self = shift;
my ($actionParams) = @_;
my $apiParams;
#公共参数
$apiParams->{AccessKeyId} = $self->accessKeyId;
$apiParams->{SignatureMethod} = $self->signatureMethod;
$apiParams->{SignatureVersion} = $self->signatureVersion;
$apiParams->{TimeStamp} = $self->timestamp;
$apiParams->{SignatureNonce} = rand;
$apiParams->{Version} = $self->version;
$apiParams->{Format} = $self->format;
#请求参数与公共参数合并
$apiParams->{$_} = $actionParams->{$_} for keys %$actionParams;
$apiParams->{Signature} = $self->compute_signature($apiParams);
my $requestUrl = $self->serverUrl . "?";
for my $key ( keys %$apiParams ) {
my $value = uri_escape_utf8 $apiParams->{$key};
$requestUrl .= "$key=" . $value . "&";
}
#删除最后一个字符&
$requestUrl = substr( $requestUrl, 0, -1 );
my $ua = LWP::UserAgent->new();
my $result = $ua->get($requestUrl);
return decode_json $result->content;
}
sub compute_signature {
my ( $self, $paramData ) = @_;
my $accessKeySecret = $self->accessKeySecret;
my $canonicalizedQueryString;
my $strArr;
for my $key ( sort keys %$paramData ) {
push @$strArr,
uri_escape_utf8($key) . "="
. uri_escape_utf8( $paramData->{$key} );
}
$canonicalizedQueryString = join "&", @$strArr;
# 生成用于计算签名的字符串 stringToSign
my $stringToSign
= 'GET&%2F&' . uri_escape_utf8($canonicalizedQueryString);
# 计算签名,注意accessKeySecret后面要加上字符'&'
my $hmac = Digest::HMAC_SHA1->new( $accessKeySecret . "&" );
$hmac->add($stringToSign);
my $signStr = $hmac->b64digest;
$signStr =~ s/$/=/g;
return $signStr;
}
1;