0

我正在尝试与 Walmart.io API 连接以从他们的资源中获取一些数据。但我被困在第一阶段。

根据 Walmart.io 快速入门文档(https://walmart.io/docs/affiliate/quick-start-guide),我应该遵循以下步骤:

  1. 在 Walmart.io 创建一个帐户
  2. 为 Web 应用程序创建应用程序
  3. 生成证书(根据他们的指南,应该有一些自动生成证书的功能,但我没有找到)
  4. 将公钥上传到应用程序
  5. 我们将获取消费者 ID 和密钥版本,使用它们以及私钥,我们可以提出请求。我们还需要添加包含 Signature 和 Timestamp 的附加标头。

所以,我做了一切,但它仍然无法正常工作。

我正在按照他们的建议使用 Open SSL 生成私钥和公钥:https : //walmart.io/key-tutorial 我尝试避免使用 -des3,这样它也不会要求我输入密码,但它没有用任何一个。

这是我尝试过的脚本

curl --location --request GET 'https://developer.api.walmart.com/api-proxy/service/affil/product/v2/taxonomy' \
--header 'WM_SEC.KEY_VERSION: 2' \
--header 'WM_CONSUMER.ID: <Consumer_ID>' \
--header 'WM_CONSUMER.INTIMESTAMP: 1594389945813' \
--header 'WM_SEC.AUTH_SIGNATURE: W5PEHIew3LsnATk0zxJddeo416YEpMIjvk1b7lW9VMIZFx55erc/5df/FK9UtS5i48q057oASo0AX3SDd2hx+QSeyiX3FtLAgAgiZnGqQ6nJndySWgL5ih/GaUTXIC6dd048GFEZlC6axXdGoTWNzX9P0n/2DwLF9EtvMjdvjB1kum0z2xKz/lQGlvnjVkGK9sZdSUa5rfgxKSPi7ix+LRIJWYwt6mTKUlGz2vP1YjGcZ7gVwAs9o8iFC//0rHUWFwaEGrT0aZJtS7fvSFtKj5NRfemX4fwRO4cgBRxPWy9MRooQwXPmKxRP75PxHKTerv8X6HvRo0GdGut+2Krqxg==' \

我得到的回应是

{
    "details": {
        "Description": "Could not authenticate in-request, auth signature :  Signature verification failed: affil-product, version: 2.0.0, env: prod",
        "wm_svc.version": "2.0.0",
        "wm_svc.name": "affil-product",
        "wm_svc.env": "prod"
    }
}

希望有人让我对这个问题有所了解。

提前致谢

4

3 回答 3

0

我以前遇到过这个问题,看起来您尝试签名的数据格式不正确。

在 node 中,模板字符串的内容应该是这样的:${consumerId}\n${timeStamp}\n${keyVersion}\n

于 2020-07-10T17:53:00.783 回答
0

原来这是生成签名的问题(这解释了为什么它在我更改脚本后起作用。

因此,这是运行良好的脚本:

<?php

use GuzzleHttp\Psr7;
use GuzzleHttp\Exception\RequestException;

class Walmart{

    private $host;

    private $consumer_id;

    private $private_key_file;

    private $headers;

    private $sec_key_version;

    private $client;

    private $options;

    public function __construct($config){
        $this->host             = $config['host'];
        $this->consumer_id      = $config['consumer_id'];
        $this->private_key_file = $config['private_key_file'];
        $this->sec_key_version  = $config['sec_key_version'];

        $this->options = array();
        
        $this->client           = new GuzzleHttp\Client();
    }
    
    public function lookup_product($publisher_id='', $ids='', $upc='', $format='json'){
        $this->load_options();

        $url_params = array(
            'format' => $format,
        );

        if($publisher_id){
            $url_params['publisher_id'] = $publisher_id;
        }

        if($ids){
            $url_params['ids'] = $ids;
        }

        if($upc){
            $url_params['upc'] = $upc;
        }

        $query = http_build_query($url_params);

        $url = $this->host . '/product/v2/items?'.$query;
        try {
            $res = $this->client->request('GET', $url, $this->options);
            $body = $res->getBody();
            if($res->getStatusCode() == 200){
                return $this->response(false, json_decode($body, true));
            }else{
                return $this->response(array(
                    'title' => 'Unable to get products',
                    'stack' => $body,
                ));
            }
        } catch (RequestException $e) {
            $err = Psr7\str($e->getRequest());

            if ($e->hasResponse()) {
                $err .= Psr7\str($e->getResponse());
            }

            return $this->response(array(
                'title' => 'Unable to get products',
                'stack' => $err,
            ));
        }
    }

    private function load_options(){
        $timestamp = time()*1000;
        $this->options = array(
            'debug' => (defined("DEBUG") && DEBUG) ? true: false,
            'headers' => array(
                'WM_SEC.KEY_VERSION'        => $this->sec_key_version,
                'WM_CONSUMER.ID'            => $this->consumer_id,
                'WM_CONSUMER.INTIMESTAMP'   => $timestamp,
                'WM_SEC.AUTH_SIGNATURE'     => $this->get_signature($timestamp),
            )
        );
    }

    private function get_signature($timestamp){

        $message = $this->consumer_id."\n".$timestamp."\n".$this->sec_key_version."\n";

        $pkeyid = openssl_pkey_get_private("file://".$this->private_key_file);

        openssl_sign($message, $signature, $pkeyid, OPENSSL_ALGO_SHA256);

        $signature = base64_encode($signature);

        openssl_free_key($pkeyid);

        return $signature;
    }

    private function response($err, $data=false){
        return array(
            'error' => $err,
            'data' => $data,
        );
    }
}

注意:它使用guzzlehttp/guzzle库进行 HTTP 请求

于 2020-07-11T09:08:10.150 回答
0

这是基于上面 Abiral 帖子的完整示例:

<?php

/**
 * Sample script to sign and send a request to the Walmart Affiliate Marketing API.
 *
 * https://walmart.io/docs/affiliate/introduction
 *
 * Usage:
 *   1. Fill out the required variables at the top of this script.
 *   2. Install dependencies via composer install.
 *   3. Run via php index.php or by opening this script in a browser.
 *
 * Acknowledgements:
 *   Abiral Neupane at https://stackoverflow.com/a/62847241/1120652
 *   @gorenstein at https://gitter.im/IO-support/community?at=5f2e5d2051bb7d3380d9b58b
 */

include './vendor/autoload.php';

use \GuzzleHttp\Client;

/**
 * Create an account at Walmart.io. Then create an application. Then follow the
 * steps at https://walmart.io/key-tutorial to create a set of keys. Upload
 * the public key (its contents start with BEGIN PUBLIC KEY) into the
 * production environment of the application that you created.
 */
$consumer_id = 'Paste here the consumer id that you will see in your application details after pasting the public key';
$key = 'Paste here the private key. Full, including BEGIN and END PRIVATE KEY lines.';

$version = '1';
$timestamp = round(microtime(true) * 1000);
$message = $consumer_id . "\n" . $timestamp . "\n" . $version . "\n";

$pkeyid = openssl_pkey_get_private($key);
openssl_sign($message, $signature, $pkeyid, OPENSSL_ALGO_SHA256);
$signature = base64_encode($signature);
openssl_free_key($pkeyid);

$api = 'https://developer.api.walmart.com';
$product_resource = 'api-proxy/service/affil/product/v2/items/316226539';
$client = new Client(['base_uri' => $api]);
$response = $client->get($product_resource, [
  'headers' => [
    'WM_SEC.KEY_VERSION' => $version,
    'WM_CONSUMER.ID' => $consumer_id,
    'WM_CONSUMER.INTIMESTAMP' => $timestamp,
    'WM_SEC.AUTH_SIGNATURE' => $signature,
  ]
]);

print_r(json_decode($response->getBody()->__toString()));

我在https://github.com/juampynr/walmart-api-v2-php上发布了上述内容

于 2021-01-27T16:39:45.120 回答