Walmart.io身份验证问题-无法在C#中对请求中的身份验证签名进行身份验证

时间:2020-09-19 06:08:50

标签: walmart-api

我正在尝试为C#实现,这是我的代码:

                WebClient downloader = new WebClient();
                downloader.Headers["WM_CONSUMER.ID"] = consumerId;
                long intimestamp = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds;
                downloader.Headers["WM_CONSUMER.INTIMESTAMP"] = intimestamp.ToString();
                downloader.Headers["WM_SEC.KEY_VERSION"] = priviateKeyVersion;
                string data = downloader.Headers["WM_CONSUMER.ID"] + "\n" + downloader.Headers["WM_CONSUMER.INTIMESTAMP"] + "\n" + downloader.Headers["WM_SEC.KEY_VERSION"] + "\n";
                downloader.Headers["WM_SEC.WM_SEC.AUTH_SIGNATURE"] = getWalmartSig(data);

                url = "https://developer.api.walmart.com/api-proxy/service/affil/product/v2/items/" + id;

                string json = downloader.DownloadString(url);

要获取签名,我使用BouncyCastle

    private string getWalmartSig(string data)
    {
        AsymmetricCipherKeyPair keyPair;
        using (var reader = File.OpenText(@"key.pem"))
        { // file containing RSA PKCS1 private key
            keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();

            RSACryptoServiceProvider key = new RSACryptoServiceProvider();
            RSAParameters rsaParam = DotNetUtilities.ToRSAParameters((RsaKeyParameters)keyPair.Public);
            ISigner signer = SignerUtilities.GetSigner("SHA256WithRSA");
            signer.Init(true, keyPair.Private);
            byte[] msg = Encoding.UTF8.GetBytes(data);
            signer.BlockUpdate(msg, 0, msg.Length);
            return Convert.ToBase64String(signer.GenerateSignature());
        }
    }

保持禁忌。请帮忙。

2 个答案:

答案 0 :(得分:1)

如果您的私钥有密码,则您必须使用另一种方法获取该对。

private static string getWalmartSig(string data)
        {
            try
            {
                AsymmetricCipherKeyPair keyPair;
                using (var reader = File.OpenText(@"key.pem")) 
                { // file containing RSA PKCS1 private key
                    keyPair = DecodePrivateKey(reader.ReadToEnd(), Constants.password);  //modified to include password for reading private key. 
                    RSACryptoServiceProvider key = new RSACryptoServiceProvider();
                    RSAParameters rsaParam = DotNetUtilities.ToRSAParameters((RsaKeyParameters)keyPair.Public);
                    ISigner signer = SignerUtilities.GetSigner("SHA256WITHRSAENCRYPTION"); //CryptoConfig.MapNameToOID("SHA256") //SHA256WithRSA //modified for using different Encryption. 
                    signer.Init(true, keyPair.Private);
                    byte[] msg = Encoding.UTF8.GetBytes(data);
                    signer.BlockUpdate(msg, 0, msg.Length);
                    return Convert.ToBase64String(signer.GenerateSignature());
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return null;
            }
        }

参考Decrypt passphrase protected PEM containing private key

 private static AsymmetricCipherKeyPair DecodePrivateKey(string encryptedPrivateKey, string password) //from https://stackoverflow.com/questions/44767290/decrypt-passphrase-protected-pem-containing-private-key
    {
        try
        {
            TextReader textReader = new StringReader(encryptedPrivateKey);
            PemReader pemReader = new PemReader(textReader, new PasswordFinder(password));
            var privateKeyObject = (AsymmetricCipherKeyPair)pemReader.ReadObject(); //modified for direct casting. 

            RsaPrivateCrtKeyParameters rsaPrivatekey = (RsaPrivateCrtKeyParameters)privateKeyObject.Private;  //modified to use the private key
            RsaKeyParameters rsaPublicKey = new RsaKeyParameters(false, rsaPrivatekey.Modulus, rsaPrivatekey.PublicExponent);
            AsymmetricCipherKeyPair kp = new AsymmetricCipherKeyPair(rsaPublicKey, rsaPrivatekey);
            return kp;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            return null;
        }
    }

现在是扩展类。参考同一个链接

private class PasswordFinder : IPasswordFinder
{
    private string password;

    public PasswordFinder(string password)
    {
        this.password = password;
    }


    public char[] GetPassword()
    {
        return password.ToCharArray();
    }
}

注意我对方法所做的更改。这应该能让你的代码运行起来。

答案 1 :(得分:1)

Olorunfemi Ajibulu 是正确的,您的 AUTH_SIGNATURE 标题名称有误。这就是为什么你会被禁止。然而,一旦你纠正了这一点,我几乎可以保证你从现在开始会得到 401。 API 似乎没有进行身份验证。