0

我正在尝试从 .NET Core 向 VISA api 发出 GET 请求,并且在 WebException 中收到以下错误消息

提供给包裹的凭据不被认可签证

VISA API 支持双向 SSL 连接,为此,visa 会颁发一组私钥和证书以及一对用户名和密码。

p12根据 VISA 文档使用以下命令创建了一个证书文件。

openssl pkcs12 -export -in cert.pem -inkey "privateKey.pem" 
    -certfile cert.pem -out myProject_keyAndCertBundle.p12

然后我编写了以下代码来向 VISA API 发出请求。我将此代码作为 .NET Core 控制台应用程序的一部分运行。

public string MakeHelloWorldCall()
{
    string requestURL = "https://sandbox.api.visa.com/vdp/helloworld";

    string userId = ConfigurationManager.AppSettings["userId"];
    string password = ConfigurationManager.AppSettings["password"];
    string certificatePath = ConfigurationManager.AppSettings["cert"];
    string certificatePassword = ConfigurationManager.AppSettings["certPassword"];
    string statusCode = "";

    HttpWebRequest request = WebRequest.Create(requestURL) as HttpWebRequest;
    request.Method = "GET";

    request.Headers["Authorization"] = GetBasicAuthHeader(userId, password);

    var certificate = new X509Certificate2(certificatePath, certificatePassword);
    request.ClientCertificates.Add(certificate);

    try
    {
        // Make the call
        // This is the line which throws the exception.
        using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
        {
            statusCode = response.StatusCode.ToString();
        }
    }
    catch (WebException e)
    {
        Console.WriteLine(e.Message);
        Exception ex = e.InnerException;

        while(ex != null)
        {
            Console.WriteLine(ex.Message);
            ex = ex.InnerException;
        }

        if (e.Response is HttpWebResponse)
        {
            HttpWebResponse response = (HttpWebResponse)e.Response;
            statusCode = response.StatusCode.ToString();
        }
    }

    return statusCode;
}

private string GetBasicAuthHeader(string userId, string password)
{
    string authString = userId + ":" + password;
    var authStringBytes = Encoding.UTF8.GetBytes(authString);
    string authHeaderString = Convert.ToBase64String(authStringBytes);
    return "Basic " + authHeaderString;
}

我在控制台中看到以下输出。

The SSL connection could not be established, see inner exception. The credentials supplied to the package were not recognized
The SSL connection could not be established, see inner exception.
The credentials supplied to the package were not recognized

所以根本错误是The credentials supplied to the package were not recognized.

我几乎被困在这里,因为我不确定是什么导致了这个错误。

我尝试在 Google 和 SO 上搜索此错误。但大多数帖子都怀疑访问证书的权限不足。但是我正在使用管理员用户帐户运行 Visual Studio,而且我使用的是证书文件,而不是机器上安装的证书。

我想任何有双向 SSL 连接和/或 VISA API 经验的人都能够理解这个错误背后的确切原因。

编辑:我能够从配置相同.p12证书和授权标头的 SOAP UI 成功调用 API。

4

3 回答 3

1

最后,我能够解决这个问题。

我做了两件事来达成决议。

  1. 使用 HttpClient 而不是 HttpWebRequest 来发出 API 请求。感谢@Fred。
  2. 我没有使用证书文件,而是在当前用户证书存储下的机器上安装了证书。

以下是工作代码。

public string MakeHelloWorldCallUsingHttpClient()
{
    string requestURL = "https://sandbox.api.visa.com/vdp/helloworld";

    string userId = ConfigurationManager.AppSettings["userId"];
    string password = ConfigurationManager.AppSettings["password"];
    string apiResponse = "";

    HttpClientHandler clientHandler = new HttpClientHandler();

    HttpClient httpClient = new HttpClient(clientHandler);
    httpClient.DefaultRequestHeaders.Authorization 
            = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", GetBasicAuthHeaderValue(userId, password));
    try
    {
        // Make the call
        var response = httpClient.GetAsync(requestURL).Result;

        if (response.StatusCode == HttpStatusCode.OK)
        {
            apiResponse = response.Content.ReadAsStringAsync().Result;
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
        Exception ex = e.InnerException;
        while (ex != null)
        {
            Console.WriteLine(ex.Message);
            ex = ex.InnerException;
        }
    }
    return apiResponse;
}

private string GetBasicAuthHeaderValue(string userId, string password)
{
    string authString = userId + ":" + password;
    var authStringBytes = Encoding.UTF8.GetBytes(authString);
    return Convert.ToBase64String(authStringBytes);
}

以下是我现在从 API 获得的输出。

{"timestamp":"2019-07-01T14:02:22","message":"helloworld"}

以下代码行确保从当前用户的证书存储中找到客户端证书。

clientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;

上述设置ClientCertificateOptionsClientCertificateOption.Manual需要手动添加证书,clientHandler.ClientCertificates如下所示。

var certificate = new X509Certificate2(certificatePath, certificatePassword);
clientHandler.ClientCertificates.Add(certificate);

这将导致与我目前面临的相同错误。

这让我认为让框架定位客户端证书是最有利的。

于 2019-07-01T14:06:09.713 回答
0

我遇到了同样的问题,终于找到了在 Visa 社区开发者网站上发布解决方案的人

https://community.developer.visa.com/t5/Two-way-SSL-X-Pay-Token/NET-Core-3-1-The-credentials-supplied-to-the-package-were-not/ td-p/14240

解决方案的要点是针对 C# 而不是使用此命令生成密钥

openssl pkcs12 -export -in cert.pem -inkey "privateKey.pem" -certfile cert.pem -out myProject_keyAndCertBundle.p12

您应该排除“-certfile”参数并使用以下内容

openssl pkcs12 -export -in cert.pem -inkey "privateKey.pem" -out myProject_keyAndCertBundle.p12 

在我的 C# 项目中,这解决了我的问题,我仍然能够从文件中加载密钥而不使用证书存储。

于 2021-03-15T08:28:46.310 回答
0

你使用完整的 IIS 吗?确保您的应用程序池有权访问此文件

如何授予权限

但是很难调试你无权访问的东西。

请检查这个答案

于 2019-07-01T13:29:07.877 回答