diff --git a/src/SKIT.FlurlHttpClient.Wechat.Ads/Exceptions/WechatAdsRequestAgencyTokenException.cs b/src/SKIT.FlurlHttpClient.Wechat.Ads/Exceptions/WechatAdsRequestAgencyTokenException.cs
new file mode 100644
index 00000000..ea3c5c7f
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.Ads/Exceptions/WechatAdsRequestAgencyTokenException.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace SKIT.FlurlHttpClient.Wechat.Ads.Exceptions
+{
+ public class WechatAdsRequestAgencyTokenException : WechatAdsException
+ {
+ ///
+ internal WechatAdsRequestAgencyTokenException()
+ {
+ }
+
+ ///
+ internal WechatAdsRequestAgencyTokenException(string message)
+ : base(message)
+ {
+ }
+
+ ///
+ internal WechatAdsRequestAgencyTokenException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.Ads/Interceptors/WechatAdsAgencyTokenInterceptor.cs b/src/SKIT.FlurlHttpClient.Wechat.Ads/Interceptors/WechatAdsRequestAgencyTokenInterceptor.cs
similarity index 76%
rename from src/SKIT.FlurlHttpClient.Wechat.Ads/Interceptors/WechatAdsAgencyTokenInterceptor.cs
rename to src/SKIT.FlurlHttpClient.Wechat.Ads/Interceptors/WechatAdsRequestAgencyTokenInterceptor.cs
index 2a6fb24a..a9a6053a 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.Ads/Interceptors/WechatAdsAgencyTokenInterceptor.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.Ads/Interceptors/WechatAdsRequestAgencyTokenInterceptor.cs
@@ -6,12 +6,12 @@ using Flurl.Http;
namespace SKIT.FlurlHttpClient.Wechat.Ads.Interceptors
{
- internal class WechatAdsAgencyTokenInterceptor : FlurlHttpCallInterceptor
+ internal class WechatAdsRequestAgencyTokenInterceptor : FlurlHttpCallInterceptor
{
private readonly string _agencyId;
private readonly string _agencyApiKey;
- public WechatAdsAgencyTokenInterceptor(string agencyId, string agencyApiKey)
+ public WechatAdsRequestAgencyTokenInterceptor(string agencyId, string agencyApiKey)
{
_agencyId = agencyId;
_agencyApiKey = agencyApiKey;
@@ -20,6 +20,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Ads.Interceptors
public override async Task BeforeCallAsync(FlurlCall flurlCall)
{
if (flurlCall == null) throw new ArgumentNullException(nameof(flurlCall));
+ if (flurlCall.Completed) throw new Exceptions.WechatAdsRequestAgencyTokenException("This interceptor must be called before request completed.");
string timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString();
string nonce = Guid.NewGuid().ToString("N");
diff --git a/src/SKIT.FlurlHttpClient.Wechat.Ads/WechatAdsClient.cs b/src/SKIT.FlurlHttpClient.Wechat.Ads/WechatAdsClient.cs
index b084afcf..02fee8f0 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.Ads/WechatAdsClient.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.Ads/WechatAdsClient.cs
@@ -30,7 +30,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Ads
FlurlClient.BaseUrl = options.Endpoints ?? WechatAdsEndpoints.DEFAULT;
FlurlClient.WithTimeout(TimeSpan.FromMilliseconds(options.Timeout));
- Interceptors.Add(new Interceptors.WechatAdsAgencyTokenInterceptor(
+ Interceptors.Add(new Interceptors.WechatAdsRequestAgencyTokenInterceptor(
agencyId: options.AgencyId,
agencyApiKey: options.AgencyApiKey
));
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs
index f7c10ee0..94985945 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientEventVerificationExtensions.cs
@@ -19,13 +19,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
/// 微信回调通知中的 Wechatpay-Signature 字段。
/// 微信回调通知中的 Wechatpay-Serial 字段。
///
- public static bool VerifyEventSignature(
- this WechatTenpayClient client,
- string callbackTimestamp,
- string callbackNonce,
- string callbackBody,
- string callbackSignature,
- string callbackSerialNumber)
+ public static bool VerifyEventSignature(this WechatTenpayClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSerialNumber)
{
return VerifyEventSignature(client, callbackTimestamp, callbackNonce, callbackBody, callbackSignature, callbackSerialNumber, out _);
}
@@ -44,14 +38,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
///
///
///
- public static bool VerifyEventSignature(
- this WechatTenpayClient client,
- string callbackTimestamp,
- string callbackNonce,
- string callbackBody,
- string callbackSignature,
- string callbackSerialNumber,
- out Exception? error)
+ public static bool VerifyEventSignature(this WechatTenpayClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSerialNumber, out Exception? error)
{
if (client == null) throw new ArgumentNullException(nameof(client));
if (callbackTimestamp == null) throw new ArgumentNullException(nameof(callbackTimestamp));
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs
index 3d0e4fb1..fca44162 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientResponseVerificationExtensions.cs
@@ -40,11 +40,55 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
if (client == null) throw new ArgumentNullException(nameof(client));
if (response == null) throw new ArgumentNullException(nameof(response));
+ return VerifyResponseSignature(client, response.WechatpayTimestamp, response.WechatpayNonce, Encoding.UTF8.GetString(response.RawBytes), response.WechatpaySignature, response.WechatpayCertificateSerialNumber, out error);
+ }
+
+ ///
+ /// 验证响应签名。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_1.shtml
+ ///
+ ///
+ ///
+ /// 。
+ ///
+ ///
+ ///
+ ///
+ public static bool VerifyResponseSignature(this WechatTenpayClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber)
+ {
+ return VerifyResponseSignature(client, responseTimestamp, responseNonce, responseBody, responseSignature, responseSerialNumber, out _);
+ }
+
+ ///
+ /// 验证响应签名。
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml
+ /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_1.shtml
+ ///
+ ///
+ ///
+ ///
+ /// 。
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static bool VerifyResponseSignature(this WechatTenpayClient client, string responseTimestamp, string responseNonce, string responseBody, string responseSignature, string responseSerialNumber, out Exception? error)
+ {
+ if (client == null) throw new ArgumentNullException(nameof(client));
+ if (responseTimestamp == null) throw new ArgumentNullException(nameof(responseTimestamp));
+ if (responseNonce == null) throw new ArgumentNullException(nameof(responseNonce));
+ if (responseBody == null) throw new ArgumentNullException(nameof(responseBody));
+ if (responseSignature == null) throw new ArgumentNullException(nameof(responseSignature));
+ if (responseSerialNumber == null) throw new ArgumentNullException(nameof(responseSerialNumber));
+
if (client.PlatformCertificateManager != null)
{
try
{
- var cert = client.PlatformCertificateManager.GetEntry(response.WechatpayCertificateSerialNumber)!;
+ var cert = client.PlatformCertificateManager.GetEntry(responseSerialNumber)!;
if (!cert.HasValue)
{
error = new Exceptions.WechatTenpayResponseVerificationException("Verify signature of response failed, because there is no platform certificate matched the serial number.");
@@ -54,8 +98,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
error = null;
return Utilities.RSAUtility.VerifyWithSHA256ByCertificate(
certificate: cert.Value.Certificate,
- plainText: GetPlainTextForSignature(response),
- signature: response.WechatpaySignature
+ plainText: GetPlainTextForSignature(timestamp: responseTimestamp, nonce: responseNonce, body: responseBody),
+ signature: responseSignature
);
}
catch (Exception ex)
@@ -69,11 +113,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
return false;
}
- private static string GetPlainTextForSignature(WechatTenpayResponse response)
+ private static string GetPlainTextForSignature(string timestamp, string nonce, string body)
{
- string timestamp = response.WechatpayTimestamp;
- string nonce = response.WechatpayNonce;
- string body = Encoding.UTF8.GetString(response.RawBytes);
return $"{timestamp}\n{nonce}\n{body}\n";
}
}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Interceptors/WechatTenpaySignInterceptor.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Interceptors/WechatTenpayRequestSignatureInterceptor.cs
similarity index 83%
rename from src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Interceptors/WechatTenpaySignInterceptor.cs
rename to src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Interceptors/WechatTenpayRequestSignatureInterceptor.cs
index c8e8aaf4..fc59e6db 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Interceptors/WechatTenpaySignInterceptor.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Interceptors/WechatTenpayRequestSignatureInterceptor.cs
@@ -6,14 +6,14 @@ using Flurl.Http;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Interceptors
{
- internal class WechatTenpaySignInterceptor : FlurlHttpCallInterceptor
+ internal class WechatTenpayRequestSignatureInterceptor : FlurlHttpCallInterceptor
{
private readonly string _scheme;
private readonly string _mchId;
private readonly string _mchCertSn;
private readonly string _mchCertPk;
- public WechatTenpaySignInterceptor(string scheme, string mchId, string mchCertSn, string mchCertPk)
+ public WechatTenpayRequestSignatureInterceptor(string scheme, string mchId, string mchCertSn, string mchCertPk)
{
_scheme = scheme;
_mchId = mchId;
@@ -24,6 +24,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Interceptors
public override async Task BeforeCallAsync(FlurlCall flurlCall)
{
if (flurlCall == null) throw new ArgumentNullException(nameof(flurlCall));
+ if (flurlCall.Completed) throw new Exceptions.WechatTenpayRequestSignatureException("This interceptor must be called before request completed.");
string method = flurlCall.HttpRequestMessage.Method.ToString().ToUpper();
string url = flurlCall.HttpRequestMessage.RequestUri?.PathAndQuery ?? string.Empty;
@@ -68,8 +69,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Interceptors
}
string auth = $"mchid=\"{_mchId}\",nonce_str=\"{nonce}\",signature=\"{signText}\",timestamp=\"{timestamp}\",serial_no=\"{_mchCertSn}\"";
- flurlCall.Request.Headers.Remove("Authorization");
- flurlCall.Request.WithHeader("Authorization", $"{_scheme} {auth}");
+ flurlCall.Request.Headers.Remove(Contants.HttpHeaders.Authorization);
+ flurlCall.Request.WithHeader(Contants.HttpHeaders.Authorization, $"{_scheme} {auth}");
}
}
}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClient.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClient.cs
index e48b3136..d7a3c35b 100644
--- a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClient.cs
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/WechatTenpayClient.cs
@@ -55,7 +55,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
FlurlClient.WithHeader(Contants.HttpHeaders.UserAgent, options.UserAgent);
FlurlClient.WithTimeout(TimeSpan.FromMilliseconds(options.Timeout));
- Interceptors.Add(new Interceptors.WechatTenpaySignInterceptor(
+ Interceptors.Add(new Interceptors.WechatTenpayRequestSignatureInterceptor(
scheme: options.SignAlgorithm,
mchId: options.MerchantId,
mchCertSn: options.MerchantCertificateSerialNumber,