mirror of
https://gitee.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat.git
synced 2025-04-05 17:37:54 +08:00
feat(tenpayv3): 适配微信支付平台公钥认证方案
This commit is contained in:
parent
cb32782476
commit
4203fe6111
@ -122,14 +122,14 @@ manager.AddEntry(new CertificateEntry("证书算法,支持 RSA/SM2 两种类
|
||||
|
||||
当然,现在的平台证书离过期还有很久,你也可以选择“偷懒”:提前下载好平台证书,在程序启动时记录一次即可。
|
||||
|
||||
每个请求模型对象会包含一个名为 `WechatpayCertificateSerialNumber` 的公共字段,本库会根据该字段的值自动尝试在证书管理器中读取证书内容,并完成请求中敏感信息字段加密:
|
||||
每个请求模型对象会包含一个名为 `WechatpaySerialNumber` 的公共字段,本库会根据该字段的值自动尝试在证书管理器中读取证书内容,并完成请求中敏感信息字段加密:
|
||||
|
||||
```csharp
|
||||
request.WechatpayCertificateSerialNumber = "平台证书序列号";
|
||||
request.WechatpaySerialNumber = "平台证书序列号";
|
||||
client.EncryptRequestSensitiveProperty(request);
|
||||
```
|
||||
|
||||
对于存在待加密敏感信息字段的请求模型对象而言,如果你不指定 `WechatpayCertificateSerialNumber` 字段的值,本库会自动从 `CertificateManager` 挑选一个离过期时间最远的证书。
|
||||
对于存在待加密敏感信息字段的请求模型对象而言,如果你不指定 `WechatpaySerialNumber` 字段的值,本库会自动从 `CertificateManager` 挑选一个离过期时间最远的证书。
|
||||
|
||||
---
|
||||
|
||||
|
@ -25,6 +25,48 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
if (client is null) throw new ArgumentNullException(nameof(client));
|
||||
if (request is null) throw new ArgumentNullException(nameof(request));
|
||||
|
||||
switch (client.PlatformAuthScheme)
|
||||
{
|
||||
case PlatformAuthScheme.Certificate:
|
||||
return EncryptRequestSensitivePropertyByCertificate<TRequest>(client, request);
|
||||
|
||||
case PlatformAuthScheme.PublicKey:
|
||||
return EncryptRequestSensitivePropertyByPublicKey<TRequest>(client, request);
|
||||
|
||||
default:
|
||||
throw new WechatTenpayException($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\".");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>异步加密请求中传入的敏感数据。该方法会改变传入的请求模型对象。</para>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<TRequest> EncryptRequestSensitivePropertyAsync<TRequest>(this WechatTenpayClient client, TRequest request, CancellationToken cancellationToken = default)
|
||||
where TRequest : WechatTenpayRequest
|
||||
{
|
||||
if (client is null) throw new ArgumentNullException(nameof(client));
|
||||
if (request is null) throw new ArgumentNullException(nameof(request));
|
||||
|
||||
switch (client.PlatformAuthScheme)
|
||||
{
|
||||
case PlatformAuthScheme.Certificate:
|
||||
return EncryptRequestSensitivePropertyByCertificateAsync<TRequest>(client, request);
|
||||
|
||||
case PlatformAuthScheme.PublicKey:
|
||||
return EncryptRequestSensitivePropertyByPublicKeyAsync<TRequest>(client, request);
|
||||
|
||||
default:
|
||||
throw new WechatTenpayException($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\".");
|
||||
}
|
||||
}
|
||||
|
||||
private static TRequest EncryptRequestSensitivePropertyByCertificate<TRequest>(this WechatTenpayClient client, TRequest request)
|
||||
where TRequest : WechatTenpayRequest
|
||||
{
|
||||
try
|
||||
{
|
||||
bool requireEncrypt = request.GetType().IsDefined(typeof(WechatTenpaySensitiveAttribute));
|
||||
@ -37,6 +79,34 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
SignSchemes.WECHATPAY2_SM2_WITH_SM3.Equals(signScheme) ? CertificateEntry.ALGORITHM_TYPE_SM2 :
|
||||
throw new WechatTenpayException($"Failed to encrypt request. Unsupported signing scheme: \"{signScheme}\".");
|
||||
|
||||
string certificate;
|
||||
if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
|
||||
{
|
||||
// 如果未在请求中指定特定的平台证书序列号,从管理器中取过期时间最远的
|
||||
IEnumerable<CertificateEntry> entries = client.PlatformCertificateManager.AllEntries()
|
||||
.Where(e => e.AlgorithmType == algorithmType)
|
||||
.OrderByDescending(e => e.ExpireTime);
|
||||
if (!entries.Any())
|
||||
{
|
||||
throw new WechatTenpayException("Failed to encrypt request, because the platform certificate manager is empty. Please make sure you have downloaded platform (NOT merchant) certificates first.");
|
||||
}
|
||||
|
||||
CertificateEntry entry = entries.First();
|
||||
certificate = entry.Certificate;
|
||||
request.WechatpaySerialNumber = entry.SerialNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果已在请求中指定特定的平台证书序列号,直接从管理器中取值
|
||||
CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(request.WechatpaySerialNumber!);
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
throw new WechatTenpayException($"Failed to encrypt request, because the platform certificate manager does not contain a certificate matched the serial number \"{request.WechatpaySerialNumber}\". Please make sure you have downloaded platform (NOT merchant) certificates first.");
|
||||
}
|
||||
|
||||
certificate = entry.Value.Certificate;
|
||||
}
|
||||
|
||||
ReflectionHelper.ReplaceObjectStringProperties(request, (_, currentProp, oldValue) =>
|
||||
{
|
||||
if (currentProp is null || !currentProp.IsDefined(typeof(WechatTenpaySensitivePropertyAttribute)))
|
||||
@ -48,34 +118,6 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
if (attribute is null)
|
||||
return (false, oldValue);
|
||||
|
||||
string certificate;
|
||||
if (string.IsNullOrEmpty(request.WechatpayCertificateSerialNumber))
|
||||
{
|
||||
// 如果未在请求中指定特定的平台证书序列号,从管理器中取过期时间最远的
|
||||
IEnumerable<CertificateEntry> entries = client.PlatformCertificateManager.AllEntries()
|
||||
.Where(e => e.AlgorithmType == algorithmType)
|
||||
.OrderByDescending(e => e.ExpireTime);
|
||||
if (!entries.Any())
|
||||
{
|
||||
throw new WechatTenpayException("Failed to encrypt request, because the platform certificate manager is empty. Please make sure you have downloaded platform (NOT merchant) certificates first.");
|
||||
}
|
||||
|
||||
CertificateEntry entry = entries.First();
|
||||
certificate = entry.Certificate;
|
||||
request.WechatpayCertificateSerialNumber = entry.SerialNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果已在请求中指定特定的平台证书序列号,直接从管理器中取值
|
||||
CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(request.WechatpayCertificateSerialNumber!);
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
throw new WechatTenpayException($"Failed to encrypt request, because the platform certificate manager does not contain a certificate matched the serial number \"{request.WechatpayCertificateSerialNumber}\". Please make sure you have downloaded platform (NOT merchant) certificates first.");
|
||||
}
|
||||
|
||||
certificate = entry.Value.Certificate;
|
||||
}
|
||||
|
||||
string newValue = GenerateEncryptedValueByCertificate(attribute.Algorithm, certificate, oldValue);
|
||||
return (true, newValue);
|
||||
});
|
||||
@ -92,30 +134,20 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>异步加密请求中传入的敏感数据。该方法会改变传入的请求模型对象。</para>
|
||||
/// </summary>
|
||||
/// <param name="client"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<TRequest> EncryptRequestSensitivePropertyAsync<TRequest>(this WechatTenpayClient client, TRequest request, CancellationToken cancellationToken = default)
|
||||
private static async Task<TRequest> EncryptRequestSensitivePropertyByCertificateAsync<TRequest>(this WechatTenpayClient client, TRequest request, CancellationToken cancellationToken = default)
|
||||
where TRequest : WechatTenpayRequest
|
||||
{
|
||||
if (client is null) throw new ArgumentNullException(nameof(client));
|
||||
if (request is null) throw new ArgumentNullException(nameof(request));
|
||||
|
||||
if (client.PlatformCertificateManager is not ICertificateManagerAsync)
|
||||
{
|
||||
// 降级为同步调用
|
||||
return Task.FromResult(EncryptRequestSensitiveProperty(client, request));
|
||||
return EncryptRequestSensitivePropertyByCertificate(client, request);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bool requireEncrypt = request.GetType().IsDefined(typeof(WechatTenpaySensitiveAttribute));
|
||||
if (!requireEncrypt)
|
||||
return Task.FromResult(request);
|
||||
return request;
|
||||
|
||||
string signScheme = client.Credentials.SignScheme;
|
||||
string algorithmType = // 签名方式与加密算法保持一致:RSA_SHA256 签名需 RSA 加密,SM3 签名需 SM2 加密
|
||||
@ -123,6 +155,36 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
SignSchemes.WECHATPAY2_SM2_WITH_SM3.Equals(signScheme) ? CertificateEntry.ALGORITHM_TYPE_SM2 :
|
||||
throw new WechatTenpayException($"Failed to encrypt request. Unsupported signing scheme: \"{signScheme}\".");
|
||||
|
||||
string certificate;
|
||||
if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
|
||||
{
|
||||
if (client.PlatformCertificateManager is null)
|
||||
throw new WechatTenpayException("Failed to encrypt request, because the platform certificate manager is not initialized.");
|
||||
|
||||
// 如果未在请求中指定特定的平台证书序列号,从管理器中取过期时间最远的
|
||||
IEnumerable<CertificateEntry> entries = await ((ICertificateManagerAsync)client.PlatformCertificateManager).AllEntriesAsync(cancellationToken).ConfigureAwait(false);
|
||||
entries = entries.Where(e => e.AlgorithmType == algorithmType).OrderByDescending(e => e.ExpireTime);
|
||||
if (!entries.Any())
|
||||
{
|
||||
throw new WechatTenpayException("Failed to encrypt request, because the platform certificate manager is empty. Please make sure you have downloaded platform (NOT merchant) certificates first.");
|
||||
}
|
||||
|
||||
CertificateEntry entry = entries.First();
|
||||
certificate = entry.Certificate;
|
||||
request.WechatpaySerialNumber = entry.SerialNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果已在请求中指定特定的平台证书序列号,直接从管理器中取值
|
||||
CertificateEntry? entry = await ((ICertificateManagerAsync)client.PlatformCertificateManager).GetEntryAsync(request.WechatpaySerialNumber!, cancellationToken).ConfigureAwait(false);
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
throw new WechatTenpayException($"Failed to encrypt request, because the platform certificate manager does not contain a certificate matched the serial number \"{request.WechatpaySerialNumber}\". Please make sure you have downloaded platform (NOT merchant) certificates first.");
|
||||
}
|
||||
|
||||
certificate = entry.Value.Certificate;
|
||||
}
|
||||
|
||||
ReflectionHelper.ReplaceObjectStringProperties(request, (_, currentProp, oldValue) =>
|
||||
{
|
||||
if (currentProp is null || !currentProp.IsDefined(typeof(WechatTenpaySensitivePropertyAttribute)))
|
||||
@ -134,50 +196,158 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
if (attribute is null)
|
||||
return (false, oldValue);
|
||||
|
||||
string certificate;
|
||||
if (string.IsNullOrEmpty(request.WechatpayCertificateSerialNumber))
|
||||
{
|
||||
if (client.PlatformCertificateManager is null)
|
||||
throw new WechatTenpayException("Failed to encrypt request, because the platform certificate manager is not initialized.");
|
||||
|
||||
// 如果未在请求中指定特定的平台证书序列号,从管理器中取过期时间最远的
|
||||
IEnumerable<CertificateEntry> entries = ((ICertificateManagerAsync)client.PlatformCertificateManager)
|
||||
.AllEntriesAsync(cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult()
|
||||
.Where(e => e.AlgorithmType == algorithmType)
|
||||
.OrderByDescending(e => e.ExpireTime);
|
||||
if (!entries.Any())
|
||||
{
|
||||
throw new WechatTenpayException("Failed to encrypt request, because the platform certificate manager is empty. Please make sure you have downloaded platform (NOT merchant) certificates first.");
|
||||
}
|
||||
|
||||
CertificateEntry entry = entries.First();
|
||||
certificate = entry.Certificate;
|
||||
request.WechatpayCertificateSerialNumber = entry.SerialNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果已在请求中指定特定的平台证书序列号,直接从管理器中取值
|
||||
CertificateEntry? entry = ((ICertificateManagerAsync)client.PlatformCertificateManager)
|
||||
.GetEntryAsync(request.WechatpayCertificateSerialNumber!, cancellationToken)
|
||||
.ConfigureAwait(false)
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
throw new WechatTenpayException($"Failed to encrypt request, because the platform certificate manager does not contain a certificate matched the serial number \"{request.WechatpayCertificateSerialNumber}\". Please make sure you have downloaded platform (NOT merchant) certificates first.");
|
||||
}
|
||||
|
||||
certificate = entry.Value.Certificate;
|
||||
}
|
||||
|
||||
string newValue = GenerateEncryptedValueByCertificate(attribute.Algorithm, certificate, oldValue);
|
||||
return (true, newValue);
|
||||
});
|
||||
|
||||
return Task.FromResult(request);
|
||||
return request;
|
||||
}
|
||||
catch (WechatTenpayException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new WechatTenpayException("Failed to encrypt request. Please see the inner exception for more details.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static TRequest EncryptRequestSensitivePropertyByPublicKey<TRequest>(this WechatTenpayClient client, TRequest request)
|
||||
where TRequest : WechatTenpayRequest
|
||||
{
|
||||
try
|
||||
{
|
||||
bool requireEncrypt = request.GetType().IsDefined(typeof(WechatTenpaySensitiveAttribute));
|
||||
if (!requireEncrypt)
|
||||
return request;
|
||||
|
||||
string signScheme = client.Credentials.SignScheme;
|
||||
string algorithmType = // 签名方式与加密算法保持一致:RSA_SHA256 签名需 RSA 加密,SM3 签名需 SM2 加密
|
||||
SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256.Equals(signScheme) ? PublicKeyEntry.ALGORITHM_TYPE_RSA :
|
||||
SignSchemes.WECHATPAY2_SM2_WITH_SM3.Equals(signScheme) ? PublicKeyEntry.ALGORITHM_TYPE_SM2 :
|
||||
throw new WechatTenpayException($"Failed to encrypt request. Unsupported signing scheme: \"{signScheme}\".");
|
||||
|
||||
string publicKey;
|
||||
if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
|
||||
{
|
||||
// 如果未在请求中指定特定的平台公钥序列号,从管理器中取第一个
|
||||
IEnumerable<PublicKeyEntry> entries = client.PlatformPublicKeyManager.AllEntries()
|
||||
.Where(e => e.AlgorithmType == algorithmType);
|
||||
if (!entries.Any())
|
||||
{
|
||||
throw new WechatTenpayException("Failed to encrypt request, because the platform public key manager is empty.");
|
||||
}
|
||||
|
||||
PublicKeyEntry entry = entries.First();
|
||||
publicKey = entry.PublicKey;
|
||||
request.WechatpaySerialNumber = entry.SerialNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果已在请求中指定特定的平台公钥序列号,直接从管理器中取值
|
||||
PublicKeyEntry? entry = client.PlatformPublicKeyManager.GetEntry(request.WechatpaySerialNumber!);
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
throw new WechatTenpayException($"Failed to encrypt request, because the platform public key manager does not contain a key matched the serial number \"{request.WechatpaySerialNumber}\".");
|
||||
}
|
||||
|
||||
publicKey = entry.Value.PublicKey;
|
||||
}
|
||||
|
||||
ReflectionHelper.ReplaceObjectStringProperties(request, (_, currentProp, oldValue) =>
|
||||
{
|
||||
if (currentProp is null || !currentProp.IsDefined(typeof(WechatTenpaySensitivePropertyAttribute)))
|
||||
return (false, oldValue);
|
||||
|
||||
WechatTenpaySensitivePropertyAttribute? attribute = currentProp
|
||||
.GetCustomAttributes<WechatTenpaySensitivePropertyAttribute>()
|
||||
.FirstOrDefault(attr => attr.Scheme == signScheme);
|
||||
if (attribute is null)
|
||||
return (false, oldValue);
|
||||
|
||||
string newValue = GenerateEncryptedValueByPublicKey(attribute.Algorithm, publicKey, oldValue);
|
||||
return (true, newValue);
|
||||
});
|
||||
|
||||
return request;
|
||||
}
|
||||
catch (WechatTenpayException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new WechatTenpayException("Failed to encrypt request. Please see the inner exception for more details.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<TRequest> EncryptRequestSensitivePropertyByPublicKeyAsync<TRequest>(this WechatTenpayClient client, TRequest request, CancellationToken cancellationToken = default)
|
||||
where TRequest : WechatTenpayRequest
|
||||
{
|
||||
if (client.PlatformPublicKeyManager is not IPublicKeyManagerAsync)
|
||||
{
|
||||
// 降级为同步调用
|
||||
return EncryptRequestSensitivePropertyByPublicKey(client, request);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bool requireEncrypt = request.GetType().IsDefined(typeof(WechatTenpaySensitiveAttribute));
|
||||
if (!requireEncrypt)
|
||||
return request;
|
||||
|
||||
string signScheme = client.Credentials.SignScheme;
|
||||
string algorithmType = // 签名方式与加密算法保持一致:RSA_SHA256 签名需 RSA 加密,SM3 签名需 SM2 加密
|
||||
SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256.Equals(signScheme) ? PublicKeyEntry.ALGORITHM_TYPE_RSA :
|
||||
SignSchemes.WECHATPAY2_SM2_WITH_SM3.Equals(signScheme) ? PublicKeyEntry.ALGORITHM_TYPE_SM2 :
|
||||
throw new WechatTenpayException($"Failed to encrypt request. Unsupported signing scheme: \"{signScheme}\".");
|
||||
|
||||
string publicKey;
|
||||
if (string.IsNullOrEmpty(request.WechatpaySerialNumber))
|
||||
{
|
||||
if (client.PlatformPublicKeyManager is null)
|
||||
throw new WechatTenpayException("Failed to encrypt request, because the platform public key manager is not initialized.");
|
||||
|
||||
// 如果未在请求中指定特定的平台公钥序列号,从管理器中第一个
|
||||
IEnumerable<PublicKeyEntry> entries = await ((IPublicKeyManagerAsync)client.PlatformPublicKeyManager).AllEntriesAsync(cancellationToken).ConfigureAwait(false);
|
||||
entries = entries.Where(e => e.AlgorithmType == algorithmType);
|
||||
if (!entries.Any())
|
||||
{
|
||||
throw new WechatTenpayException("Failed to encrypt request, because the platform public key manager is empty.");
|
||||
}
|
||||
|
||||
PublicKeyEntry entry = entries.First();
|
||||
publicKey = entry.PublicKey;
|
||||
request.WechatpaySerialNumber = entry.SerialNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果已在请求中指定特定的平台公钥序列号,直接从管理器中取值
|
||||
PublicKeyEntry? entry = await ((IPublicKeyManagerAsync)client.PlatformPublicKeyManager).GetEntryAsync(request.WechatpaySerialNumber!, cancellationToken).ConfigureAwait(false);
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
throw new WechatTenpayException($"Failed to encrypt request, because the platform public key manager does not contain a key matched the serial number \"{request.WechatpaySerialNumber}\".");
|
||||
}
|
||||
|
||||
publicKey = entry.Value.PublicKey;
|
||||
}
|
||||
|
||||
ReflectionHelper.ReplaceObjectStringProperties(request, (_, currentProp, oldValue) =>
|
||||
{
|
||||
if (currentProp is null || !currentProp.IsDefined(typeof(WechatTenpaySensitivePropertyAttribute)))
|
||||
return (false, oldValue);
|
||||
|
||||
WechatTenpaySensitivePropertyAttribute? attribute = currentProp
|
||||
.GetCustomAttributes<WechatTenpaySensitivePropertyAttribute>()
|
||||
.FirstOrDefault(attr => attr.Scheme == signScheme);
|
||||
if (attribute is null)
|
||||
return (false, oldValue);
|
||||
|
||||
string newValue = GenerateEncryptedValueByPublicKey(attribute.Algorithm, publicKey, oldValue);
|
||||
return (true, newValue);
|
||||
});
|
||||
|
||||
return request;
|
||||
}
|
||||
catch (WechatTenpayException)
|
||||
{
|
||||
@ -194,22 +364,44 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
switch (algorithm)
|
||||
{
|
||||
case EncryptionAlgorithms.RSA_2048_ECB_PKCS8_OAEP_WITH_SHA1_AND_MGF1:
|
||||
return RSAUtility.EncryptWithECBByCertificate(
|
||||
certificatePem: certificate,
|
||||
case EncryptionAlgorithms.RSA_2048_ECB_PKCS1:
|
||||
{
|
||||
string publicKey = RSAUtility.ExportPublicKeyFromCertificate(certificate);
|
||||
return GenerateEncryptedValueByPublicKey(algorithm, publicKey, value);
|
||||
}
|
||||
|
||||
case EncryptionAlgorithms.SM2_C1C3C2_ASN1:
|
||||
{
|
||||
string publicKey = SM2Utility.ExportPublicKeyFromCertificate(certificate);
|
||||
return GenerateEncryptedValueByPublicKey(algorithm, publicKey, value);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new WechatTenpayException($"Failed to encrypt request. Unsupported encryption algorithm: \"{algorithm}\".");
|
||||
}
|
||||
}
|
||||
|
||||
private static string GenerateEncryptedValueByPublicKey(string algorithm, string publicKey, string value)
|
||||
{
|
||||
switch (algorithm)
|
||||
{
|
||||
case EncryptionAlgorithms.RSA_2048_ECB_PKCS8_OAEP_WITH_SHA1_AND_MGF1:
|
||||
return RSAUtility.EncryptWithECB(
|
||||
publicKeyPem: publicKey,
|
||||
plainData: value,
|
||||
paddingMode: RSAUtility.PADDING_MODE_OAEPWITHSHA1ANDMGF1
|
||||
)!;
|
||||
|
||||
case EncryptionAlgorithms.RSA_2048_ECB_PKCS1:
|
||||
return RSAUtility.EncryptWithECBByCertificate(
|
||||
certificatePem: certificate,
|
||||
return RSAUtility.EncryptWithECB(
|
||||
publicKeyPem: publicKey,
|
||||
plainData: value,
|
||||
paddingMode: RSAUtility.PADDING_MODE_PKCS1
|
||||
)!;
|
||||
|
||||
case EncryptionAlgorithms.SM2_C1C3C2_ASN1:
|
||||
return SM2Utility.EncryptByCertificate(
|
||||
certificatePem: certificate,
|
||||
return SM2Utility.Encrypt(
|
||||
publicKeyPem: publicKey,
|
||||
plainData: value,
|
||||
asn1Encoding: true
|
||||
)!;
|
||||
|
@ -35,7 +35,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
responseBody: Encoding.UTF8.GetString(response.GetRawBytes()),
|
||||
responseSignature: response.WechatpaySignature,
|
||||
responseSignatureType: response.WechatpaySignatureType,
|
||||
responseSerialNumber: response.WechatpayCertificateSerialNumber
|
||||
responseSerialNumber: response.WechatpaySerialNumber
|
||||
);
|
||||
}
|
||||
|
||||
@ -124,7 +124,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
responseBody: Encoding.UTF8.GetString(response.GetRawBytes()),
|
||||
responseSignature: response.WechatpaySignature,
|
||||
responseSignatureType: response.WechatpaySignatureType,
|
||||
responseSerialNumber: response.WechatpayCertificateSerialNumber,
|
||||
responseSerialNumber: response.WechatpaySerialNumber,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
}
|
||||
|
@ -14,42 +14,98 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
{
|
||||
if (client is null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(strSerialNumber);
|
||||
if (!entry.HasValue)
|
||||
switch (client.PlatformAuthScheme)
|
||||
{
|
||||
return ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate matched the serial number \"{strSerialNumber}\"."));
|
||||
}
|
||||
case PlatformAuthScheme.Certificate:
|
||||
{
|
||||
CertificateEntry? entry = client.PlatformCertificateManager.GetEntry(strSerialNumber);
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
return ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate matched the serial number \"{strSerialNumber}\"."));
|
||||
}
|
||||
|
||||
return GenerateSignatureResultByCertificate(
|
||||
scheme: strSignScheme,
|
||||
certificate: entry.Value.Certificate,
|
||||
message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
|
||||
signature: strSignature
|
||||
);
|
||||
return GenerateSignatureResultByCertificate(
|
||||
scheme: strSignScheme,
|
||||
certificate: entry.Value.Certificate,
|
||||
message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
|
||||
signature: strSignature
|
||||
);
|
||||
}
|
||||
|
||||
case PlatformAuthScheme.PublicKey:
|
||||
{
|
||||
PublicKeyEntry? entry = client.PlatformPublicKeyManager.GetEntry(strSerialNumber);
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
return ErroredResult.Fail(new Exception($"The platform public key manager does not contain a key matched the serial number \"{strSerialNumber}\"."));
|
||||
}
|
||||
|
||||
return GenerateSignatureResultByPublicKey(
|
||||
scheme: strSignScheme,
|
||||
publicKey: entry.Value.PublicKey,
|
||||
message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
|
||||
signature: strSignature
|
||||
);
|
||||
}
|
||||
|
||||
default:
|
||||
return ErroredResult.Fail(new Exception($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\"."));
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<ErroredResult> VerifySignatureAsync(this WechatTenpayClient client, string strTimestamp, string strNonce, string strContent, string strSignature, string strSignScheme, string strSerialNumber, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (client is null) throw new ArgumentNullException(nameof(client));
|
||||
|
||||
if (client.PlatformCertificateManager is not ICertificateManagerAsync)
|
||||
switch (client.PlatformAuthScheme)
|
||||
{
|
||||
// 降级为同步调用
|
||||
return VerifySignature(client, strTimestamp, strNonce, strContent, strSignature, strSignScheme, strSerialNumber);
|
||||
}
|
||||
case PlatformAuthScheme.Certificate:
|
||||
{
|
||||
if (client.PlatformCertificateManager is not ICertificateManagerAsync)
|
||||
{
|
||||
// 降级为同步调用
|
||||
return VerifySignature(client, strTimestamp, strNonce, strContent, strSignature, strSignScheme, strSerialNumber);
|
||||
}
|
||||
|
||||
CertificateEntry? entry = await ((ICertificateManagerAsync)client.PlatformCertificateManager).GetEntryAsync(strSerialNumber, cancellationToken).ConfigureAwait(false);
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
return ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate matched the serial number \"{strSerialNumber}\"."));
|
||||
}
|
||||
CertificateEntry? entry = await ((ICertificateManagerAsync)client.PlatformCertificateManager).GetEntryAsync(strSerialNumber, cancellationToken).ConfigureAwait(false);
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
return ErroredResult.Fail(new Exception($"The platform certificate manager does not contain a certificate matched the serial number \"{strSerialNumber}\"."));
|
||||
}
|
||||
|
||||
return GenerateSignatureResultByCertificate(
|
||||
scheme: strSignScheme,
|
||||
certificate: entry.Value.Certificate,
|
||||
message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
|
||||
signature: strSignature
|
||||
);
|
||||
return GenerateSignatureResultByCertificate(
|
||||
scheme: strSignScheme,
|
||||
certificate: entry.Value.Certificate,
|
||||
message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
|
||||
signature: strSignature
|
||||
);
|
||||
}
|
||||
|
||||
case PlatformAuthScheme.PublicKey:
|
||||
{
|
||||
if (client.PlatformCertificateManager is not IPublicKeyManagerAsync)
|
||||
{
|
||||
// 降级为同步调用
|
||||
return VerifySignature(client, strTimestamp, strNonce, strContent, strSignature, strSignScheme, strSerialNumber);
|
||||
}
|
||||
|
||||
PublicKeyEntry? entry = await ((IPublicKeyManagerAsync)client.PlatformPublicKeyManager).GetEntryAsync(strSerialNumber, cancellationToken).ConfigureAwait(false);
|
||||
if (!entry.HasValue)
|
||||
{
|
||||
return ErroredResult.Fail(new Exception($"The platform public key manager does not contain a key matched the serial number \"{strSerialNumber}\"."));
|
||||
}
|
||||
|
||||
return GenerateSignatureResultByPublicKey(
|
||||
scheme: strSignScheme,
|
||||
publicKey: entry.Value.PublicKey,
|
||||
message: GenerateMessageForSignature(timestamp: strTimestamp, nonce: strNonce, body: strContent),
|
||||
signature: strSignature
|
||||
);
|
||||
}
|
||||
|
||||
default:
|
||||
return ErroredResult.Fail(new Exception($"Unsupported platform auth scheme: \"{client.PlatformAuthScheme}\"."));
|
||||
}
|
||||
}
|
||||
|
||||
private static string GenerateMessageForSignature(string timestamp, string nonce, string body)
|
||||
@ -58,6 +114,42 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
}
|
||||
|
||||
private static ErroredResult GenerateSignatureResultByCertificate(string scheme, string certificate, string message, string signature)
|
||||
{
|
||||
string publicKey = string.Empty;
|
||||
|
||||
switch (scheme)
|
||||
{
|
||||
case SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256:
|
||||
{
|
||||
try
|
||||
{
|
||||
publicKey = Utilities.RSAUtility.ExportPublicKeyFromCertificate(certificate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ErroredResult.Fail(ex);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SignSchemes.WECHATPAY2_SM2_WITH_SM3:
|
||||
{
|
||||
try
|
||||
{
|
||||
publicKey = Utilities.SM2Utility.ExportPublicKeyFromCertificate(certificate);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ErroredResult.Fail(ex);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return GenerateSignatureResultByPublicKey(scheme, publicKey, message, signature);
|
||||
}
|
||||
|
||||
private static ErroredResult GenerateSignatureResultByPublicKey(string scheme, string publicKey, string message, string signature)
|
||||
{
|
||||
ErroredResult result;
|
||||
|
||||
@ -67,8 +159,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
{
|
||||
try
|
||||
{
|
||||
bool valid = Utilities.RSAUtility.VerifyWithSHA256ByCertificate(
|
||||
certificatePem: certificate,
|
||||
bool valid = Utilities.RSAUtility.VerifyWithSHA256(
|
||||
publicKeyPem: publicKey,
|
||||
messageData: message,
|
||||
encodingSignature: new EncodedString(signature, EncodingKinds.Base64)
|
||||
);
|
||||
@ -88,8 +180,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
{
|
||||
try
|
||||
{
|
||||
bool valid = Utilities.SM2Utility.VerifyWithSM3ByCertificate(
|
||||
certificatePem: certificate,
|
||||
bool valid = Utilities.SM2Utility.VerifyWithSM3(
|
||||
publicKeyPem: publicKey,
|
||||
messageData: message,
|
||||
encodingSignature: new EncodedString(signature, EncodingKinds.Base64)
|
||||
);
|
||||
|
@ -23,16 +23,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings
|
||||
/// </summary>
|
||||
public string AlgorithmType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取证书内容(CRT/CER PEM 格式,即 -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----)
|
||||
/// </summary>
|
||||
public string Certificate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取证书序列号。
|
||||
/// </summary>
|
||||
public string SerialNumber { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取证书内容(CRT/CER PEM 格式,即 -----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----)
|
||||
/// </summary>
|
||||
public string Certificate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取生效时间。
|
||||
/// </summary>
|
||||
|
@ -0,0 +1,18 @@
|
||||
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信支付平台认证方案。
|
||||
/// </summary>
|
||||
public enum PlatformAuthScheme
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用平台证书进行认证。
|
||||
/// </summary>
|
||||
Certificate = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 使用平台公钥进行认证。
|
||||
/// </summary>
|
||||
PublicKey = 1
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
using System;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示一个微信商户平台公钥实体。
|
||||
/// </summary>
|
||||
public partial struct PublicKeyEntry : IEquatable<PublicKeyEntry>
|
||||
{
|
||||
/// <summary>
|
||||
/// 公钥算法类型:RSA。
|
||||
/// </summary>
|
||||
public const string ALGORITHM_TYPE_RSA = CertificateEntry.ALGORITHM_TYPE_RSA;
|
||||
|
||||
/// <summary>
|
||||
/// 公钥算法类型:SM2。
|
||||
/// </summary>
|
||||
public const string ALGORITHM_TYPE_SM2 = CertificateEntry.ALGORITHM_TYPE_SM2;
|
||||
|
||||
/// <summary>
|
||||
/// 获取公钥算法类型。
|
||||
/// 取值范围:RSA、SM2。
|
||||
/// </summary>
|
||||
public string AlgorithmType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取公钥序列号。
|
||||
/// </summary>
|
||||
public string SerialNumber { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取公钥内容(CRT/CER PEM 格式,即 -----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----)
|
||||
/// </summary>
|
||||
public string PublicKey { get; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="algorithmType"></param>
|
||||
/// <param name="serialNumber"></param>
|
||||
/// <param name="publicKey"></param>
|
||||
[Newtonsoft.Json.JsonConstructor]
|
||||
[System.Text.Json.Serialization.JsonConstructor]
|
||||
public PublicKeyEntry(string algorithmType, string serialNumber, string publicKey)
|
||||
{
|
||||
publicKey = publicKey?.Trim()!;
|
||||
|
||||
if (string.IsNullOrEmpty(algorithmType))
|
||||
throw new ArgumentException("The value of `algorithmType` can not be empty.", nameof(algorithmType));
|
||||
if (string.IsNullOrEmpty(publicKey))
|
||||
throw new ArgumentException("The value of `publicKey` can not be empty.", nameof(publicKey));
|
||||
if (string.IsNullOrEmpty(serialNumber))
|
||||
throw new ArgumentException("The value of `serialNumber` can not be empty.", nameof(serialNumber));
|
||||
if (!ALGORITHM_TYPE_RSA.Equals(algorithmType) && !ALGORITHM_TYPE_SM2.Equals(algorithmType))
|
||||
throw new ArgumentException("The value of `algorithmType` an invalid value.", nameof(algorithmType));
|
||||
if (!(publicKey.StartsWith("-----BEGIN PUBLIC KEY-----") && publicKey.EndsWith("-----END PUBLIC KEY-----")))
|
||||
throw new ArgumentException("The value of `publicKey` is an invalid public key file content.", nameof(publicKey));
|
||||
|
||||
AlgorithmType = algorithmType;
|
||||
SerialNumber = serialNumber.ToUpper();
|
||||
PublicKey = publicKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
/// <returns></returns>
|
||||
public bool Equals(PublicKeyEntry other)
|
||||
{
|
||||
return string.Equals(AlgorithmType, other.AlgorithmType) &&
|
||||
string.Equals(PublicKey, other.PublicKey) &&
|
||||
string.Equals(SerialNumber, other.SerialNumber);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
return false;
|
||||
if (GetType() != obj.GetType())
|
||||
return false;
|
||||
|
||||
return Equals((PublicKeyEntry)obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
#if NETCOREAPP || NET5_0_OR_GREATER
|
||||
return HashCode.Combine(AlgorithmType?.GetHashCode(), PublicKey?.GetHashCode(), SerialNumber?.GetHashCode());
|
||||
#else
|
||||
return (AlgorithmType?.GetHashCode(), PublicKey?.GetHashCode(), SerialNumber?.GetHashCode()).GetHashCode();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool operator ==(PublicKeyEntry left, PublicKeyEntry right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public static bool operator !=(PublicKeyEntry left, PublicKeyEntry right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信商户平台公钥管理器接口。
|
||||
/// </summary>
|
||||
public interface IPublicKeyManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取存储的全部公钥实体。
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerable<PublicKeyEntry> AllEntries();
|
||||
|
||||
/// <summary>
|
||||
/// 添加一个公钥实体。
|
||||
/// </summary>
|
||||
/// <param name="entry"></param>
|
||||
void AddEntry(PublicKeyEntry entry);
|
||||
|
||||
/// <summary>
|
||||
/// 根据公钥序列号获取公钥实体。
|
||||
/// </summary>
|
||||
/// <param name="serialNumber"></param>
|
||||
/// <returns></returns>
|
||||
PublicKeyEntry? GetEntry(string serialNumber);
|
||||
|
||||
/// <summary>
|
||||
/// 根据公钥序列号移除公钥实体。
|
||||
/// </summary>
|
||||
/// <param name="serialNumber"></param>
|
||||
/// <returns></returns>
|
||||
bool RemoveEntry(string serialNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信商户平台公钥管理器异步接口。
|
||||
/// </summary>
|
||||
public interface IPublicKeyManagerAsync : IPublicKeyManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步获取存储的全部公钥实体。
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<PublicKeyEntry>> AllEntriesAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步添加一个公钥实体。
|
||||
/// </summary>
|
||||
/// <param name="entry"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task AddEntryAsync(PublicKeyEntry entry, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据公钥序列号获取公钥实体。
|
||||
/// </summary>
|
||||
/// <param name="serialNumber"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<PublicKeyEntry?> GetEntryAsync(string serialNumber, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步根据公钥序列号移除公钥实体。
|
||||
/// </summary>
|
||||
/// <param name="serialNumber"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> RemoveEntryAsync(string serialNumber, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 一个基于内存实现的 <see cref="IPublicKeyManager"/>。
|
||||
/// </summary>
|
||||
public sealed class InMemoryPublicKeyManager : IPublicKeyManager
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, PublicKeyEntry> _dict;
|
||||
|
||||
public InMemoryPublicKeyManager()
|
||||
{
|
||||
_dict = new ConcurrentDictionary<string, PublicKeyEntry>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<PublicKeyEntry> AllEntries()
|
||||
{
|
||||
return _dict.Values.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void AddEntry(PublicKeyEntry entry)
|
||||
{
|
||||
_dict.AddOrUpdate(entry.SerialNumber, (_) => entry, (_, _) => entry);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PublicKeyEntry? GetEntry(string serialNumber)
|
||||
{
|
||||
if (_dict.TryGetValue(serialNumber, out PublicKeyEntry entry))
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool RemoveEntry(string serialNumber)
|
||||
{
|
||||
return _dict.TryRemove(serialNumber, out _);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,16 +12,28 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
/// </summary>
|
||||
public class WechatTenpayClient : CommonClientBase, ICommonClient
|
||||
{
|
||||
private static readonly string ASSEMBLY_VERSION = Assembly.GetAssembly(typeof(WechatTenpayClient))!.GetName()!.Version!.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前客户端使用的微信支付商户凭证。
|
||||
/// </summary>
|
||||
public Settings.Credentials Credentials { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前客户端使用的微信支付平台认证方案。
|
||||
/// </summary>
|
||||
public Settings.PlatformAuthScheme PlatformAuthScheme { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前客户端使用的微信支付平台证书管理器。
|
||||
/// </summary>
|
||||
public Settings.ICertificateManager PlatformCertificateManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前客户端使用的微信支付平台公钥管理器。
|
||||
/// </summary>
|
||||
public Settings.IPublicKeyManager PlatformPublicKeyManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取是否自动加密请求中的敏感信息字段。
|
||||
/// </summary>
|
||||
@ -53,14 +65,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
if (options is null) throw new ArgumentNullException(nameof(options));
|
||||
|
||||
Credentials = new Settings.Credentials(options);
|
||||
PlatformAuthScheme = options.PlatformAuthScheme;
|
||||
PlatformCertificateManager = options.PlatformCertificateManager;
|
||||
PlatformPublicKeyManager = options.PlatformPublicKeyManager;
|
||||
AutoEncryptRequestSensitiveProperty = options.AutoEncryptRequestSensitiveProperty;
|
||||
AutoDecryptResponseSensitiveProperty = options.AutoDecryptResponseSensitiveProperty;
|
||||
|
||||
FlurlClient.BaseUrl = options.Endpoint ?? WechatTenpayEndpoints.DEFAULT;
|
||||
FlurlClient.WithHeader(HttpHeaders.Accept, "application/json");
|
||||
FlurlClient.WithHeader(HttpHeaders.AcceptLanguage, options.AcceptLanguage);
|
||||
FlurlClient.WithHeader(HttpHeaders.UserAgent, $"OS/{Environment.OSVersion.Platform} SKIT.FlurlHttpClient.Wechat.Tenpay/{Assembly.GetAssembly(typeof(WechatTenpayClient))!.GetName().Version}");
|
||||
FlurlClient.WithHeader(HttpHeaders.UserAgent, $"OS/{Environment.OSVersion.Platform} SKIT.FlurlHttpClient.Wechat.Tenpay/{ASSEMBLY_VERSION}");
|
||||
FlurlClient.WithTimeout(options.Timeout <= 0 ? Timeout.InfiniteTimeSpan : TimeSpan.FromMilliseconds(options.Timeout));
|
||||
|
||||
Interceptors.Add(new Interceptors.WechatTenpayRequestSigningInterceptor(
|
||||
@ -87,9 +101,9 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
this.EncryptRequestSensitiveProperty(request);
|
||||
}
|
||||
|
||||
if (request.WechatpayCertificateSerialNumber is not null)
|
||||
if (request.WechatpaySerialNumber is not null)
|
||||
{
|
||||
flurlRequest.WithHeader("Wechatpay-Serial", request.WechatpayCertificateSerialNumber);
|
||||
flurlRequest.WithHeader("Wechatpay-Serial", request.WechatpaySerialNumber);
|
||||
}
|
||||
|
||||
return flurlRequest;
|
||||
|
@ -73,12 +73,32 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
/// </summary>
|
||||
public bool AutoDecryptResponseSensitiveProperty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置微信支付平台认证方案。
|
||||
/// <para>默认值:<see cref="Settings.PlatformAuthScheme.Certificate"/></para>
|
||||
/// </summary>
|
||||
public Settings.PlatformAuthScheme PlatformAuthScheme { get; set; } = Settings.PlatformAuthScheme.Certificate;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置微信支付平台证书管理器。
|
||||
/// <para>
|
||||
/// 仅当 <see cref="PlatformAuthScheme"/> 的值为 <see cref="Settings.PlatformAuthScheme.Certificate"/> 时有效。
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 默认值:<see cref="Settings.InMemoryCertificateManager"/>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public Settings.ICertificateManager PlatformCertificateManager { get; set; } = new Settings.InMemoryCertificateManager();
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置微信支付平台公钥管理器。
|
||||
/// <para>
|
||||
/// 仅当 <see cref="PlatformAuthScheme"/> 的值为 <see cref="Settings.PlatformAuthScheme.PublicKey"/> 时有效。
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 默认值:<see cref="Settings.InMemoryPublicKeyManager"/>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public Settings.IPublicKeyManager PlatformPublicKeyManager { get; set; } = new Settings.InMemoryPublicKeyManager();
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
using System;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
{
|
||||
/// <summary>
|
||||
@ -8,8 +10,16 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
/// <summary>
|
||||
/// 获取或设置微信请求使用的微信支付平台证书序列号。
|
||||
/// </summary>
|
||||
[Obsolete("后续版本该属性将被移除,请使用 `WechatpaySerialNumber` 属性替代。", error: true)]
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public virtual string? WechatpayCertificateSerialNumber { get; set; }
|
||||
public virtual string? WechatpayCertificateSerialNumber { get { return WechatpaySerialNumber; } set { WechatpaySerialNumber = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置微信请求使用的微信支付平台证书或公钥序列号。
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public virtual string? WechatpaySerialNumber { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
@ -66,9 +67,17 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
|
||||
/// <summary>
|
||||
/// 获取微信应答签名使用的微信支付平台证书序列号。
|
||||
/// </summary>
|
||||
[Obsolete("后续版本该属性将被移除,请使用 `WechatpaySerialNumber` 属性替代。", error: true)]
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public string WechatpayCertificateSerialNumber { get { return GetRawHeaders().GetFirstValueOrEmpty("Wechatpay-Serial"); } }
|
||||
public string WechatpayCertificateSerialNumber { get { return WechatpaySerialNumber; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取微信应答签名使用的微信支付平台证书或公钥序列号。
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public string WechatpaySerialNumber { get { return GetRawHeaders().GetFirstValueOrEmpty("Wechatpay-Serial"); } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个值,该值指示调用微信 API 是否成功。
|
||||
|
@ -38,7 +38,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.CertificateName!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.CertificateId!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.CertificateName!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -83,7 +83,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Contact!.ContactName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Contact!.MobileNumber!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Contact!.Email!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
|
@ -41,7 +41,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.AccountNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.AccountName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.AccountNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -130,7 +130,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UBOList![0].IdName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UBOList![0].IdNumber!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UBOList![0].IdAddress!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -249,7 +249,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Subject!.UBOList![0].IdAddress!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.BankAccount!.AccountName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.BankAccount!.AccountNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -308,7 +308,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.ReceiverList![0].Name!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.ReceiverList![0].Name!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -361,7 +361,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.AccountNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.AccountNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -474,7 +474,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UBOList![0].IdAddress!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.BankAccount!.AccountName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.BankAccount!.AccountNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -527,7 +527,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.UserName!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserName!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -586,7 +586,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.ReceiverList![0].Name!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.ReceiverList![0].Name!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -639,7 +639,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.UserName!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserName!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -695,7 +695,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.RealName!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.BankAccountNumber!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.RealName!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -763,7 +763,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Identity!.CredentialNumber!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.BankCard!.BankCardNumber!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.BankCard!.MobileNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -816,7 +816,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.MobileNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.MobileNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -872,7 +872,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.MerchantContactInformation!.ConsultationPhoneNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.MerchantContactInformation!.ConsultationPhoneNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -944,7 +944,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.PayeeInfo!.BankAccount!.AccountNumber));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.PayeeInfo!.Identity!.IdName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.PayeeInfo!.Identity!.IdNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1000,7 +1000,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.IdCardNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.PhoneNumber!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.IdCardNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1056,7 +1056,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.IdCardNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.IdCardNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1115,7 +1115,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.Buyer!.UserEmail!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Buyer!.UserMobileNumber!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Buyer!.UserEmail!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1174,7 +1174,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.Buyer!.UserEmail!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Buyer!.UserMobileNumber!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Buyer!.UserEmail!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1233,7 +1233,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.RealIdentity!.IdCardNumber);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.RealIdentity!.RealName));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.RealIdentity!.IdCardNumber));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1292,7 +1292,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.RealIdentity!.IdCardNumber);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.RealIdentity!.RealName));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.RealIdentity!.IdCardNumber));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1351,7 +1351,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.RealIdentity!.IdCardNumber);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.RealIdentity!.RealName));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.RealIdentity!.IdCardNumber));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1407,7 +1407,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.IdCardNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.IdCardNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1463,7 +1463,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.IdCardNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.IdCardNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1519,7 +1519,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.IdCardNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.IdCardNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1571,7 +1571,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
static void AssertMockRequestModel(Models.ApplyPlatformSolutionMerchantTransferReservationRequest request, Func<string, string> decryptor)
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.UserName!);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1630,7 +1630,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.ReceiverList![0].Name!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.ReceiverList![0].Name!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1683,7 +1683,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.Name!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Name!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1739,7 +1739,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.RealName!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.BankAccountNumber!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.RealName!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1795,7 +1795,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.UserMobile!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserMobile!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1848,7 +1848,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
{
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.UserMobile!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserMobile!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1904,7 +1904,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.UserMobile!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.UserMobile!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -1960,7 +1960,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.DriverIdCardNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.DriverName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.DriverIdCardNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -2022,7 +2022,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotEqual(MOCK_PLAIN_STR, request.TransferDetailList![0].UserIdCardNumber!);
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.TransferDetailList![0].UserName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.TransferDetailList![0].UserIdCardNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
@ -2084,7 +2084,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Identify!.RealName!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.Identify!.CredentialNumber!));
|
||||
Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.BankCardNumber!));
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpayCertificateSerialNumber!, ignoreCase: true);
|
||||
Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
|
||||
|
@ -22,7 +22,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotNull(response.WechatpayTimestamp);
|
||||
Assert.NotNull(response.WechatpaySignature);
|
||||
Assert.NotNull(response.WechatpaySignatureType);
|
||||
Assert.NotNull(response.WechatpayCertificateSerialNumber);
|
||||
Assert.NotNull(response.WechatpaySerialNumber);
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "测试用例:验证响应签名(基于 SM2)")]
|
||||
@ -41,7 +41,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
|
||||
Assert.NotNull(response.WechatpayTimestamp);
|
||||
Assert.NotNull(response.WechatpaySignature);
|
||||
Assert.NotNull(response.WechatpaySignatureType);
|
||||
Assert.NotNull(response.WechatpayCertificateSerialNumber);
|
||||
Assert.NotNull(response.WechatpaySerialNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user