【问题标题】:Perl hash to oauth signaturePerl 哈希到 oauth 签名
【发布时间】:2017-08-09 02:14:22
【问题描述】:

我找到了一个如何制作 oauth 签名的示例,但遇到了多维哈希问题。我的哈希看起来像这样,使用 Data::Dumper 显示我的哈希,称为 %request:

$VAR1 = { 'Invoice' => { 'Line' => [ { 'Id' => '1', 'SalesItemLineDetail' => { 'ItemRef' => { 'value' => 'SKM2267' }, 'UnitPrice' => '10.00' }, 'DetailType' => 'SalesItemLineDetail', 'LineNum' => 1 }, { 'Id' => '2', 'SalesItemLineDetail' => { 'ItemRef' => { 'value' => 'SKM2292' }, 'UnitPrice' => '20.00' }, 'DetailType' => 'SalesItemLineDetail', 'LineNum' => 2 }, { 'Id' => '3', 'SalesItemLineDetail' => { 'ItemRef' => { 'value' => 'SKM2285' }, 'UnitPrice' => '30.00' }, 'DetailType' => 'SalesItemLineDetail', 'LineNum' => 3 } ], 'DocNumber' => '90210', 'CustomerRef' => \{ 'name' => 'Amazon.com', 'value' => 1 } } };

制作签名的例子包括将上面的 %request 哈希加入一个字符串:

my $string = join('&',map {$_ . '=' . uri_escape($request{$_})} sort keys %request);

但这会产生以下与用作签名不一致的情况:

Invoice=HASH%280x7f254c17b540%29

如何处理此哈希以创建需要传递到我的 oauth 签名字符串的字符串?

运行良好的示例脚本使用以下内容构建 oauth 签名:

my $hmac = Digest::HMAC_SHA1->new($e->{params}{qbo_consumer_secret} . '&' . $e->{params}{qbo_access_token_secret});
$hmac->add('GET&' . uri_escape('https://sandbox-quickbooks.api.intuit.com/v3/company/' . $company_id . '/query') . '&' . uri_escape('oauth_consumer_key=' . $consumer_key . '&oauth_nonce=' . $nonce . '&oauth_signature_method=HMAC-SHA1&oauth_timestamp=' . $time . '&oauth_token=' . $access_token . '&oauth_version=1.0' . '&' . join('&',map {$_ . '=' . uri_escape($params{$_})} sort keys %params)));

与我正在尝试的相比:

my $hmac = Digest::HMAC_SHA1->new($e->{params}{qbo_consumer_secret} . '&' . $e->{params}{qbo_access_token_secret});
$hmac->add('POST&' . uri_escape($server) . '&' . uri_escape('oauth_consumer_key=' . $e->{params}{qbo_consumer_key}) . '&oauth_nonce=' . $nonce . '&oauth_signature_method=HMAC-SHA1&oauth_timestamp=' . $time . '&oauth_token=' . $e->{params}{qbo_access_token} . '&oauth_version=1.0' . '&' . join('&',map {$_ . '=' . uri_escape($request{$_})} sort keys %request));

那么请求包含这个授权头:

my $req = HTTP::Request->new(POST => $server);
$req->header(Authorization =>
    'OAuth oauth_consumer_key="' . $e->{qbo_consumer_key}
    . '",oauth_nonce="' . $nonce
    . '",oauth_signature="' . encode_base64($hmac->digest)
    . '",oauth_signature_method="HMAC-SHA1'
    . '",oauth_timestamp="' . time();
    . '",oauth_token="' . $e->{qbo_access_token}
    . '",oauth_version="1.0'
    . '"');
$req->content( \%request );

此外,尝试将散列转换为 json 会导致“无法编码对标量的引用”。我试试这个简单的测试脚本:

#!/usr/bin/perl

use strict;
use warnings;
use JSON;

my %hash = { 'Invoice' => { 'Line' => [ { 'Id' => '1', 'SalesItemLineDetail' => { 'ItemRef' => { 'value' => 'SKM2267' }, 'UnitPrice' => '10.00' }, 'DetailType' => 'SalesItemLineDetail', 'LineNum' => 1 }, { 'Id' => '2', 'SalesItemLineDetail' => { 'ItemRef' => { 'value' => 'SKM2292' }, 'UnitPrice' => '20.00' }, 'DetailType' => 'SalesItemLineDetail', 'LineNum' => 2 }, { 'Id' => '3', 'SalesItemLineDetail' => { 'ItemRef' => { 'value' => 'SKM2285' }, 'UnitPrice' => '30.00' }, 'DetailType' => 'SalesItemLineDetail', 'LineNum' => 3 } ], 'DocNumber' => '90210', 'CustomerRef' => \{ 'name' => 'Amazon.com', 'value' => 1 } } };

my $js = encode_json \%hash;
print "$js\n";

在下面产生这个错误,我的哈希有什么问题吗?

Reference found where even-sized list expected at testjson.pl line 8.
{"HASH(0x8db5f3c)":null}

【问题讨论】:

  • 您到底想uri_escape 做什么? $request{$_} 是一个哈希引用,通常不是你想要字符串化的那种东西。
  • 是的,我想我不需要 uri_escape,我下面的示例使用 HMAC 包添加函数来构造 GET 请求的签名,但我正在为这个特定的 Quickbooks API 使用 POST称呼。如何生成字符串也让我感到困惑,但据我了解,该请求必须是 oauth 签名的一部分。我将添加与我正在尝试做的事情相比有效的示例。
  • 在工作示例中,签名是由构成 HTTP 请求的元素构成的 - 方法、主机和查询字符串。您如何使用%request 构建$req
  • 是的,作为内容,我已经在上面添加了。我没有任何运气使用 JSON 包将哈希转换为 json 字符串。没有使用 $json->encode(%request); 给我整个哈希值。

标签: perl hash oauth


【解决方案1】:

首先,如果您阅读 JSON 模块文档,它非常清楚地指出 encode 方法只接受一个标量,因此传递它一个哈希是行不通的。当您将这样的哈希传递给函数时,它会获取每个键和值并分别传递它们。

my %hash=("a" => 1,"b" => 2);
my_func(%hash);
# The above function call is the same as the one below
my_func("b",2,"a",1);

它传递每个键/值对的顺序是随机的,就像您通常使用散列找到的那样。它甚至应该抛出一个错误,告诉你如何使用它,或者至少我安装的版本在我尝试测试你的代码时是这样的。

相反,你真正想要做的是像这样传递 hashref

$json->encode(\%request);

返回的值是您需要传递给$req->content() 并在签名中使用的值。我不知道 Quickbooks API 的任何内容,不知道您是打算按原样传递 JSON 数据还是将其用作 CGI 参数的值。我希望它应该在他们的文档中告诉你。

【讨论】:

  • 其实我已经试过我的 $js = $json->encode(\%request);并得到这个错误:无法编码对标量的引用。我会在上面添加更多内容。
  • @rwfitzy 您创建的散列不正确 - 最外层的散列是用括号而不是大括号创建的。有关如何创建哈希的示例,请参阅我的答案。内部是用大括号完成的
猜你喜欢
  • 2017-04-25
  • 2014-06-18
  • 1970-01-01
  • 1970-01-01
  • 2020-12-08
  • 2013-12-20
  • 2013-08-10
  • 1970-01-01
相关资源
最近更新 更多