在PHP中生成OAuth 1签名

9
我正在尝试连接LivePerson Engagement History API,但遇到了一个问题,我认为与生成的签名有关。
首先,API已经提供了必要的消费者密钥、消费者密钥、访问令牌和令牌密钥。因此,我不必去检索它们。为了访问他们的API,我只需要提供授权标头。我使用Postman模拟了所有内容,并且一切都正常工作。问题出现在我尝试在我的类中生成自己的时间戳/随机数/签名时。
以下是从我的类中发送cURL请求的方法:
private function execute($options = array())
{
    if (!isset($options['url'])) {
        return;
    }

    $ch = curl_init($options['url']);

    $method = (isset($options['method'])) ? $options['method'] : 'GET';

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);

    if (isset($options['auth']) && $options['auth']) {
        $timestamp = round(microtime(true) * 1000);
        $nonce = $this->getNonce(11);
        $version = "1.0";
        $signatureMethod = "HMAC-SHA1";
        $signature = $this->generateSignature($options, $timestamp, $nonce, $signatureMethod, $version);

        $authHeader = "Authorization: OAuth oauth_consumer_key=\"{$this->consumerKey}\",oauth_token=\"{$this->accessToken}\",oauth_signature_method=\"{$signatureMethod}\",oauth_timestamp=\"{$timestamp}\",oauth_nonce=\"{$nonce}\",oauth_version=\"{$version}\",oauth_signature=\"{$signature}\"";

        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            $authHeader,
            "Content-Type: application/json"
        ));
    }

    if (isset($options['body']) && !empty($options['body'])) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($options['body']));
    }

    $result = curl_exec($ch);
    curl_close($ch);

    return $result;
}

我从 https://github.com/BaglerIT/OAuthSimple/blob/master/src/OAuthSimple.php 直接复制了 getNonce 方法。

这是我编写的生成签名的方法(从各种SO帖子和其他来源拼凑而成):

protected function generateSignature($request, $timestamp, $nonce, $signatureMethod, $version)
{
    $base = $request['method'] . "&" . rawurlencode($request['url']) . "&"
        . rawurlencode("oauth_consumer_key=" . rawurlencode($this->consumerKey)
        . "&oauth_nonce=" . rawurlencode($nonce)
        . "&oauth_signature_method=" . rawurlencode($signatureMethod)
        . "&oauth_timestamp=" . $timestamp
        . "&oauth_version=" . $version);

    $key = rawurlencode($this->consumerSecret) . '&' . rawurlencode($this->tokenSecret);
    $signature = base64_encode(hash_hmac('sha1', $base, $key, true));

    return $signature;
}

我实际上可以将Postman中的授权头复制并粘贴到我的$authHeader变量中,并替换除时间戳/随机数/签名之外的所有内容,这样就可以正常工作。
我从他们的服务器收到的响应是[code] => 0005,但我在他们的文档中找不到有关响应代码的任何信息。
编辑:我忘了查看响应头 - 准确的错误是无效的签名。
5个回答

8
我做了两个更改使其能够正常工作。
  1. 在创建签名的基本字符串时,我漏掉了oauth_token参数。
  2. 根据OAuth Core 1.0文档,“按名称进行排序,使用字节值的词典顺序。”
因此,我最终重新排列参数以按字母顺序排序。下面是生成基本字符串的代码:
$base = $request['method'] . "&" . rawurlencode($request['url']) . "&"
        . rawurlencode("oauth_consumer_key=" . rawurlencode($this->consumerKey)
        . "&oauth_nonce=" . rawurlencode($nonce)
        . "&oauth_signature_method=" . rawurlencode($signatureMethod)
        . "&oauth_timestamp=" . rawurlencode($timestamp)
        . "&oauth_token=" . rawurlencode($this->accessToken)
        . "&oauth_version=" . rawurlencode($version));

我还重新排列了身份验证头部中的参数,以与基本字符串的顺序相匹配:

$authHeader = "Authorization: OAuth oauth_consumer_key=\"{$this->consumerKey}\",oauth_nonce=\"{$nonce}\",oauth_signature_method=\"{$signatureMethod}\",oauth_timestamp=\"{$timestamp}\",oauth_token=\"{$this->accessToken}\",oauth_version=\"{$version}\",oauth_signature=\"{$signature}\"";

嘿,我也遇到了同样的问题,看了你的代码后 Oauth_signature 看起来没问题。但是我收到的响应是 bad request 400。你能帮我解决一下吗? - matheen ulla

2
$base = $request['method']
        . '&' . rawurlencode($request['url'])
        . '&' . rawurlencode('oauth_consumer_key=' . $this->consumerKey)
        . rawurlencode('&oauth_nonce=' . $nonce)
        . rawurlencode('&oauth_signature_method=' . $signatureMethod)
        . rawurlencode('&oauth_timestamp=' . $timestamp)
        . rawurlencode('&oauth_version=' . $version)
        . rawurlencode('&' . http_build_query($data));

$key = rawurlencode($this->consumerSecret) . '&';

$signature = rawurlencode(base64_encode(hash_hmac('SHA1', $base, $key, true)));

如果您进行POST请求,请确保包含您发布的数据,否则签名将无法验证。
CURLOPT_HTTPHEADER => array(
    "authorization: OAuth oauth_consumer_key=\"{$consumerKey}\",oauth_signature_method=\"{$signatureMethod}\",oauth_timestamp=\"{$timestamp}\",oauth_nonce=\"{$nonce}\",oauth_version=\"{$version}\",oauth_signature=\"{$oauthSignature}\"",
    "content-type: application/x-www-form-urlencoded",
  ),

并且标题应该如上所述


1

这个修复版本对我有效:

function generateOauthSignature($method, $url, $consumerKey, $nonce, $signatureMethod, $timestamp, $version, $consumerSecret, $tokenSecret, $tokenValue, $extraParams = array())
    {
        $base = strtoupper($method) . "&" . rawurlencode($url) . "&"
            . rawurlencode("oauth_consumer_key=" . $consumerKey
            . "&oauth_nonce=" . $nonce
            . "&oauth_signature_method=" . $signatureMethod
            . "&oauth_timestamp=" . $timestamp
            . "&oauth_token=" . $tokenValue
            . "&oauth_version=" . $version);

            if (!empty($extraParams)) {
                $base .= rawurlencode("&" . http_build_query($extraParams));
            }

        $key = rawurlencode($consumerSecret) . '&' . rawurlencode($tokenSecret);
        $signature = base64_encode(hash_hmac('sha1', $base, $key, true));

        return rawurlencode($signature);
    }

以下 Twitter 线程对我很有帮助: https://twittercommunity.com/t/how-to-generate-oauth-signature-when-post-json-body-in-php/87581


0

此版本与OAuth PECL库的功能相匹配,因此您不再需要它。

public static function oauth_get_sbs(
    $requestMethod,
    $requestURL,
    $request_parameters
): string
{
    return $requestMethod . "&" . rawurlencode($requestURL) . "&"
        . rawurlencode("oauth_consumer_key=" . rawurlencode($request_parameters['oauth_consumer_key'])
            . "&oauth_nonce=" . rawurlencode($request_parameters['oauth_nonce'])
            . "&oauth_signature_method=" . rawurlencode($request_parameters['oauth_signature_method'])
            . "&oauth_timestamp=" . $request_parameters['oauth_timestamp']
            . "&oauth_token=" . $request_parameters['oauth_token']
            . "&oauth_version=" . $request_parameters['oauth_version']);
}

0

我也曾经在正确设置OAuth 1签名方面苦苦挣扎,尝试了很多次都失败了。在TGA的提示下,我研究了一下Twitter是如何做的,发现有一个现成的类可以直接使用:

TwitterAPIExchange.php来自https://github.com/J7mbo/twitter-api-php仓库。

即使它被称为“Twitter...”,它也可以用于其他OAuth1 API。调用将如下所示:

$settings = array(
    'oauth_access_token' => TOKEN,
    'oauth_access_token_secret' => TOKEN_SECRET,
    'consumer_key' => CONSUMER_KEY,
    'consumer_secret' => CONSUMER_SECRET
);
$url = "https://api-url.com/api/v4/users/0451432/";
$requestMethod = 'POST';
$postfields = array(
    'groupIds' => '23,24,25',
);

$twitter = new TwitterAPIExchange($settings);
return $twitter->buildOauth($url, $requestMethod)
       ->setPostfields($postfields)
       ->performRequest();

对我来说它完美地运作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接