我真的会把头发拉出来。这应该不难实现,但无论如何我无法让它工作。我正在尝试实施瑞典 Swish API 进行支付。我们所需要的只是发送一个有效载荷并向 HttpClientHandler 添加一个证书。
我正在尝试按照此处所述实施 PaymentRequest 方法:https ://developer.swish.nu/api/payment-request/v2
我的代码如下,首先是一个配置类:
public class SwishApiDetails
{
public string BaseUrl { get; set; } // Base URL for the API
public string CallbackUrl { get; set; } // Optional callback URL
public string ClientCertificate { get; set; } // Client certificate thumbprint
public string RootCertificateV1 { get; set; } // First CA certificate
public string RootCertificateV2 { get; set; } // Second CA certificate
}
实际 API 调用的代码(是的,我知道我没有处理客户端,但这不是现在的问题(除非是这样))
public class SwishApi
{
private readonly HttpClient _client;
private readonly SwishApiDetails _configuration;
public SwishApi(SwishApiDetails configuration)
{
_configuration = configuration;
var handler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (
sender,
certificate,
chain,
sslPolicyErrors) => true,
ClientCertificateOptions = ClientCertificateOption.Manual
};
var thumbprints = new List<string>
{
_configuration.ClientCertificate,
_configuration.RootCertificateV1,
_configuration.RootCertificateV2
};
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
foreach (var thumbprint in thumbprints)
{
var certificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
handler.ClientCertificates.AddRange(certificates);
}
_client = new HttpClient(handler) {BaseAddress = new Uri(_configuration.BaseUrl)};
}
public async Task<(bool HasError, string Message)> MakePaymentRequest(
int amountToPay,
string reference,
string phoneNumber,
string receiverAlias,
string messageToCustomer)
{
var phoneAlias = phoneNumber.Replace(" ", "").Replace("+", "");
if (phoneAlias.StartsWith("0")) phoneAlias = phoneAlias.Substring(1, phoneAlias.Length);
var result = await _client.SendAsync(new HttpRequestMessage
{
Method = HttpMethod.Put,
RequestUri = new Uri($"{_configuration.BaseUrl}/api/v2/paymentrequests/{reference}"),
Content = JsonContent.Create(new
{
amount = amountToPay,
payerAlias = phoneAlias,
payeeAlias = receiverAlias,
message = messageToCustomer,
payeePaymentReference = reference,
currency = SwishDefaults.Currency.Sek,
callbackUrl = _configuration.CallbackUrl
})
});
return result.IsSuccessStatusCode
? (false, string.Empty)
: (true, await result.Content.ReadAsStringAsync());
}
}
为了测试这一切,我正在使用这段代码:
public class Test
{
private readonly SwishApi _swish;
public Test()
{
_swish = new SwishApi(new SwishApiDetails
{
BaseUrl = "https://cpc.getswish.net/swish-cpcapi",
CallbackUrl = null,
ClientCertificate = "F06644FAF53150D5B31716ABF121FE112A225AF1", // Local thumbprint
RootCertificateV1 = "A8985D3A65E5E5C4B2D7D66D40C6DD2FB19C5436", // Local thumbprint
RootCertificateV2 = "03BFF7B54C712504C5BE5A8528163C931618A3C0" // Local thumbprint
});
}
[Fact]
public async Task TestPaymentRequest()
{
var (hasError, _) = await _swish.MakePaymentRequest(
1,
Guid.NewGuid().ToString("N").ToUpper(),
"4671111111",
"Swish Test",
"Testing");
Assert.False(hasError);
}
}
它们对于测试环境是公开的。
证书不是由真正的 CA 签发的,它们是由 Swish 自己签名的,因此可能存在一些问题。除此之外,我真的不知道出了什么问题以及为什么其他人可以让它工作。
它可能是特定于操作系统的,还是我机器上的密码套件被破坏了?
如果你想试试这个,去这个 repo:https ://github.com/lhammarstrom/swish-net
如果您想使用本地证书文件进行尝试,则可以转到此分支:https ://github.com/lhammarstrom/swish-net/tree/feature/with_cert (feature/with_cert)。客户端证书包含在测试项目的文件中。
另外,为了澄清,我得到的错误是:
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
System.Net.Http.HttpRequestException
The SSL connection could not be established, see inner exception.
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
at Swish.Services.SwishApi.MakePaymentRequest(Int32 amountToPay, String reference, String phoneNumber, String receiverAlias, String messageToCustomer) in /Users/leni/Projects/Swish/Swish/Services/SwishApi.cs:line 73
at Swish.Tests.Test.TestPaymentRequest() in /Users/leni/Projects/Swish/Swish.Tests/Tests.cs:line 30
at Xunit.Sdk.TestInvoker`1.<>c__DisplayClass48_1.<<InvokeTestMethodAsync>b__1>d.MoveNext() in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\Frameworks\Runners\TestInvoker.cs:line 264
--- End of stack trace from previous location ---
at Xunit.Sdk.ExecutionTimer.AggregateAsync(Func`1 asyncAction) in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\Frameworks\ExecutionTimer.cs:line 48
at Xunit.Sdk.ExceptionAggregator.RunAsync(Func`1 code) in C:\Dev\xunit\xunit\src\xunit.core\Sdk\ExceptionAggregator.cs:line 90
System.Security.Authentication.AuthenticationException
Authentication failed, see inner exception.
at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
Interop+AppleCrypto+SslException
handshake failure
Exception doesn't have a stacktrace
编辑:
我已遵循本指南(https://johan.driessen.se/posts/Calling-the-Swish-Payment-API-from-Azure-AppService/)。他们让它工作,我没有。此外,这个声称可以在 .NET 5 ( https://github.com/RickardPettersson/swish-api-csharp ) 上运行的存储库也无法在我的机器上运行。