1

我正在尝试为 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());
        }
    }

继续被禁止。请帮忙。

4

2 回答 2

1

Olorunfemi Ajibulu 是正确的,您的 AUTH_SIGNATURE 标头名称有错字。这就是为什么你得到一个禁止。但是,一旦您纠正了这一点,我几乎可以保证您将从现在开始获得 401。API 似乎没有进行身份验证。

于 2021-03-03T03:00:47.410 回答
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;
            }
        }

请参阅解密包含私钥的密码保护 PEM以供参考。

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

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

于 2021-02-27T22:04:20.267 回答