Payfast API 401 错误 C#。商户授权失败

问题描述 投票:0回答:2

我目前正在尝试 Ping Payfast API 以获得基本身份验证率。

我认为我一直在努力让签名正确。

生成我的签名

按字母顺序对所有变量进行排序(如此处所示)和 URLencoding

string signature = HttpUtility.UrlEncode($"merchant-id={merchantID}&passphrase=​{passphrase}&timestamp={timestamp}&version={version}");

然后我生成 MD5 哈希字符串,如下所示

using (var md5Hash = MD5.Create())
{
    // Byte array representation of source string
    var sourceBytes = Encoding.UTF8.GetBytes(signature);
    
    // Generate hash value(Byte Array) for input data
    var hashBytes = md5Hash.ComputeHash(sourceBytes);

    // Convert hash byte array to string
    var hash = BitConverter.ToString(hashBytes).Replace("-", string.Empty);

    // Output the MD5 hash
    Console.WriteLine(signature + " is: " + hash);
    string hashlower = hash.ToLower()
}

然后我将签名添加到标题中

request.AddHeader("merchant-id", merchantID);
request.AddHeader("version", version);
request.AddHeader("signature", hashlower);
request.AddHeader("timestamp", timestamp);

在查看邮递员集合中的示例时,这似乎是正确的 https://documenter.getpostman.com/view/10608852/TVCmSQZu

有人能发现我在签名生成中做错的事情吗

完整代码

string timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH\\:mm\\:ss", CultureInfo.InvariantCulture);
string signature = HttpUtility.UrlEncode($"merchant-id={merchantID}&passphrase=​{passphrase}&timestamp={timestamp}&version={version}");

using (var md5Hash = MD5.Create())
{
    // Byte array representation of source string
    var sourceBytes = Encoding.UTF8.GetBytes(signature);

    // Generate hash value(Byte Array) for input data
    var hashBytes = md5Hash.ComputeHash(sourceBytes);

    // Convert hash byte array to string
    var hash = BitConverter.ToString(hashBytes).Replace("-", string.Empty);

    // Output the MD5 hash
    Console.WriteLine(signature + " is: " + hash);
    string hashlower = hash.ToLower();

    var client = new RestClient("https://api.payfast.co.za/ping");
    client.Timeout = -1;

    var request = new RestRequest(Method.GET);
    request.AddHeader("merchant-id", merchantID);
    request.AddHeader("version", version);
    request.AddHeader("signature", hashlower);
    request.AddHeader("timestamp", timestamp);
              
    IRestResponse response = client.Execute(request);

    Console.WriteLine(response.Content);
}
c# asp.net api md5 payfast
2个回答
0
投票

我获取了 API 文档,并在复制后逐行转换匹配所有内容,并运行其 Node.jsPython 示例代码。

我的发现中有两件事。

URL 编码。

当您在c#中进行URL编码时,例如您的日期:
2023-02-20T20:00:00变为2023-02-20T20%3a00%3a00

来自 Python 和 Node.js 的

PayFast 编码为大写,因此:
2023-02-20T20:00:00 变为 2023-02-20T20%3A00%3A00

注意后一个实例中的 'A',确保您的 URL 编码正确。
使用

Uri.EscapeDataString([string])

哈希编码:

您假设 C# 中使用 UTF-8 的编码与 Node.js 和 Python 中的加密哈希相同,在花时间研究所有变体后,它实际上是 ASCII。更新以下内容:

var sourceBytes = Encoding.UTF8.GetBytes(signature);

以下内容:

var sourceBytes = Encoding.ASCII.GetBytes(signature);

十六进制你的哈希值!

在返回哈希值之前,您还需要对其进行十六进制处理

var sb = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
{
     sb.Append(b.ToString("x2")); // x2 is lowercase
}
signature = sb.ToString();

将所有内容包装到一个漂亮的全局方法中,并以

SortedList<string,string>
作为输入,迭代这些值,用
StringBuilder
将它们串起来,MD5 对其进行哈希处理,然后返回您的签名。

(是的,当您在 TKey 字符串上输入值时,

SortedList<TKey,TValue>
会自动对列表进行排序,这是 API 文档中的要求。


0
投票

这是一个有效的实现,其中“数据”包含密码。

    private string GenerateSignature(Dictionary<string, string> data)
{
    var orderedData = new SortedList<string, string>(data);
    
    var getString = 
        string.Join("&", orderedData.Select(item => $"{item.Key}={Uri.EscapeDataString(item.Value)}"));

    using var md5 = MD5.Create();
    var hashedBytes = md5.ComputeHash(Encoding.ASCII.GetBytes(getString));
    
    var sb = new StringBuilder(hashedBytes.Length * 2);
    foreach (byte b in hashedBytes)
    {
        sb.Append(b.ToString("x2"));
    }
    return sb.ToString();
}
© www.soinside.com 2019 - 2024. All rights reserved.