How to generate WM_SEC.AUTH_SIGNATURE?

一笑奈何 提交于 2021-01-23 01:52:07

问题


Does anyone have python code that can generate this header for the Walmart API?

WM_SEC.AUTH_SIGNATURE

I have tried to wrap my head around the java example but I am not having any luck of it as I have no Java experience.

If anyone knows the format of the string that needs to be signed I could probably figure it out from there.

How do I solve the problem?


回答1:


Below example for Affiliates API on PHP

String (message) for sign

$message = self::WM_CONSUMER_ID . "\n" . $milliseconds . "\n" . self::WM_SEC_KEY_VERSION . "\n";

PHP Example class

<?php

declare(strict_types=1);

namespace WalmartBundle\Services;


use phpseclib\Crypt\RSA;

/**
 * Class WalmartAuthSignature
 *
 *  Thanks: https://github.com/fillup/walmart-auth-signature-php/blob/develop/src/Signature.php
 *
 * @package WalmartBundle\Services
 */
class WalmartAuthSignature
{
    public static function sign(string $message, string $privateKey): string
    {
        $rsa = new RSA();

        $decodedPrivateKey = base64_decode($privateKey);
        $rsa->setPrivateKeyFormat(RSA::PRIVATE_FORMAT_PKCS8);
        $rsa->setPublicKeyFormat(RSA::PRIVATE_FORMAT_PKCS8);

        if ($rsa->loadKey($decodedPrivateKey, RSA::PRIVATE_FORMAT_PKCS8)) {
            $rsa->setHash('sha256');
            $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
            $signed = $rsa->sign($message);

            return base64_encode($signed);
        }

        throw new \Exception('Unable to load private key');
    }
}



回答2:


Be aware that this method of Authentication will no longer work soon.

We are deprecating Digital Signature-based Authentication (Consumer ID and Private Key) on August 28, 2019. If you are currently using this method, your API calls will not work after August 28, 2019.

But if you still wish to try it:

From the API documentation

To get the digital signature using your own code, follow these steps:

  1. Get the Consumer ID and your Base 64-encoded Private Key you generated in Seller Center.
  2. Get the full URL you wish to call, including any path and query parameters.
  3. Use the GET method to construct an input for the digital signature.
  4. Use the structure listed below:
  • The Consumer ID issued to you_ + "\n" +
  • the URL of the API call you are making + "\n" +
  • the request method of the API call you are making in all capitals + "\n" +
  • the Unix Epoch timestamp now (in milliseconds since Jan 01 1970 UTC) + "\n"

** Note: The order of the parameters and the line returns \n are important to generate the signature properly

  1. Generate the byte array of the structured data listed in step 3 using the following steps: a. Decode the byte array with Base-64.

    b. Encode the resulting value using PKCS#8 to represent your Private Key. Libraries in various languages offer the ability to identify that the Private Key is in PKCS#8 format and not in other conflicting formats such as PKCS#1. c. Use this byte representation of your private key to sign the data using SHA-256 with RSA. d. Encode the generated digital signature using Base-64.

  2. Use the generated digital signature and the timestamp to make your API call.




回答3:


Here is the code that I ended up using to get the authorization to work if anyone needs it:

import requests, json, pprint, time
from requests.auth import HTTPBasicAuth
import errno
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
import hashlib
import base64


ACCOUNT_SID = 'xxxxxx'
AUTH_TOKEN = 'xxxxxxxx'
BASE_URL = 'https://products.api.impactradius.com/Mediapartners/{}/'.format(ACCOUNT_SID)
API_PATH = 'Catalogs/4277'
consumerId = 'xxxxxxxx'
epoxTime = str(int(time.time()*1000))
keyVersion = '1'

URL = 'https://developer.api.walmart.com/api-proxy/service/affil/product/v2/items'


hashDict = { 'WM_CONSUMER.ID' : consumerId,
            'WM_CONSUMER.INTIMESTAMP' : epoxTime,
            'WM_SEC.KEY_VERSION' : keyVersion
            }
sortedHashString = hashDict['WM_CONSUMER.ID'] +'\n'+ hashDict['WM_CONSUMER.INTIMESTAMP'] +'\n'+ hashDict['WM_SEC.KEY_VERSION']+'\n'
encodedHashString = sortedHashString.encode()

try:
    with open('./WM_IO_private_key.pem', 'r') as f:
        key = RSA.importKey(f.read())
except IOError as e:
    print(e)

hasher = SHA256.new(encodedHashString)
signer = PKCS1_v1_5.new(key)
signature = signer.sign(hasher)

signature_enc = str(base64.b64encode(signature),'utf-8')

headers = { 'WM_CONSUMER.ID' : consumerId,
            'WM_CONSUMER.INTIMESTAMP' : epoxTime,
            'WM_SEC.AUTH_SIGNATURE' : signature_enc,
            'WM_SEC.KEY_VERSION' : keyVersion,
            'WM_QOS.CORRELATION_ID' : 'afjksldkfj4r8ojfns',
            'WM_IFX.CLIENT_TYPE' : 'INTERNAL',
            'WM_PREVIEW' : 'false',
            'WM_SHOW_REASON_CODES' : 'ALL',
            'Content-Type' : 'application/json',
            }

params = {
            'category' : '4171_1228385',
            'publisherId' : 'xxxxxxxxxxx'
        }

response = requests.get(URL, headers=headers, params=params)

jsonData = json.loads(response.text)


来源:https://stackoverflow.com/questions/57383902/how-to-generate-wm-sec-auth-signature

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!