【问题标题】:Generating OAuth 1 Signature in PHP在 PHP 中生成 OAuth 1 签名
【发布时间】:2022-01-31 01:54:26
【问题描述】:

我正在尝试连接到LivePerson Engagement History API,但我遇到了一个我认为与正在生成的签名有关的问题。

首先,API 已经提供了必要的消费者密钥、消费者秘密、访问令牌和令牌秘密。所以我不必经历检索这些的过程。为了访问他们的 API,我只需要provide the auth header。我已经使用 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;
}

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

这是我为生成签名而编写的方法(由各种 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,但我在他们的文档中找不到任何关于响应代码的内容。

编辑:我错过了查看响应标头 - 确切的错误是无效签名。

【问题讨论】:

    标签: php oauth


    【解决方案1】:

    我改变了两件事来让它工作。

    1. 我在为签名创建基本字符串时缺少oauth_token
    2. 根据OAuth Core 1.0 documentation,“参数按名称排序,使用字典字节值排序。”

    所以我最终将参数重新排序为按字母顺序排列。下面是生成基本字符串的代码最终的样子:

    $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));
    

    我还重新排序了 auth 标头中的参数以匹配基本字符串的顺序:

    $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}\"";
    

    【讨论】:

      【解决方案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",
        ),
      

      并且标题应该如上

      【讨论】:

        【解决方案3】:

        这个固定版本对我有用:

        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);
            }
        

        以下推特帖子帮助了我:https://twittercommunity.com/t/how-to-generate-oauth-signature-when-post-json-body-in-php/87581

        【讨论】:

          【解决方案4】:

          我还在为正确设置 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();
          

          它非常适合我。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-03-17
            • 1970-01-01
            • 2012-09-08
            • 1970-01-01
            • 2021-12-19
            • 1970-01-01
            • 2011-03-27
            相关资源
            最近更新 更多