【问题标题】:Walmart.io authentication issue - Could not authenticate in-request, auth signature in C#Walmart.io 身份验证问题 - 无法在 C# 中验证请求中的身份验证签名
【发布时间】:2020-09-19 06:08:50
【问题描述】:

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

继续被禁止。请帮忙。

【问题讨论】:

    标签: walmart-api


    【解决方案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();
        }
    }
    

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

    【讨论】:

    • 感谢您的帮助。我没有私钥的密码。但是我也尝试了使用空密码或随机密码的方法,它将获得与使用我的方法相同的私钥。我可以看到私钥中的所有数字为:DP、DQ、指数、模数、p、q。所以我认为解码私钥是没有问题的。我尝试了 SHA256WITHRSAENCRYPTION 并得到了相同的结果。
    • 你能确认这是正确的吗? WM_SEC.WM_SEC.AUTH_SIGNATURE ?标题中应该是“WM_SEC.AUTH_SIGNATURE”..
    • @XiangyuCao ,检查header key是否签名。
    • 你是对的。这么愚蠢的错误。现在可以了。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2020-10-31
      • 2012-05-01
      • 2022-06-28
      • 1970-01-01
      • 2022-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多