refactor: clean code

This commit is contained in:
Fu Diwei 2022-03-11 10:38:15 +08:00
parent 6010c202e8
commit 23d144fef7
7 changed files with 84 additions and 30 deletions

View File

@ -0,0 +1,24 @@
using System;
namespace SKIT.FlurlHttpClient.Wechat.Ads.Exceptions
{
public class WechatAdsRequestAgencyTokenException : WechatAdsException
{
/// <inheritdoc/>
internal WechatAdsRequestAgencyTokenException()
{
}
/// <inheritdoc/>
internal WechatAdsRequestAgencyTokenException(string message)
: base(message)
{
}
/// <inheritdoc/>
internal WechatAdsRequestAgencyTokenException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

View File

@ -6,12 +6,12 @@ using Flurl.Http;
namespace SKIT.FlurlHttpClient.Wechat.Ads.Interceptors namespace SKIT.FlurlHttpClient.Wechat.Ads.Interceptors
{ {
internal class WechatAdsAgencyTokenInterceptor : FlurlHttpCallInterceptor internal class WechatAdsRequestAgencyTokenInterceptor : FlurlHttpCallInterceptor
{ {
private readonly string _agencyId; private readonly string _agencyId;
private readonly string _agencyApiKey; private readonly string _agencyApiKey;
public WechatAdsAgencyTokenInterceptor(string agencyId, string agencyApiKey) public WechatAdsRequestAgencyTokenInterceptor(string agencyId, string agencyApiKey)
{ {
_agencyId = agencyId; _agencyId = agencyId;
_agencyApiKey = agencyApiKey; _agencyApiKey = agencyApiKey;
@ -20,6 +20,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Ads.Interceptors
public override async Task BeforeCallAsync(FlurlCall flurlCall) public override async Task BeforeCallAsync(FlurlCall flurlCall)
{ {
if (flurlCall == null) throw new ArgumentNullException(nameof(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 timestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString();
string nonce = Guid.NewGuid().ToString("N"); string nonce = Guid.NewGuid().ToString("N");

View File

@ -30,7 +30,7 @@ namespace SKIT.FlurlHttpClient.Wechat.Ads
FlurlClient.BaseUrl = options.Endpoints ?? WechatAdsEndpoints.DEFAULT; FlurlClient.BaseUrl = options.Endpoints ?? WechatAdsEndpoints.DEFAULT;
FlurlClient.WithTimeout(TimeSpan.FromMilliseconds(options.Timeout)); FlurlClient.WithTimeout(TimeSpan.FromMilliseconds(options.Timeout));
Interceptors.Add(new Interceptors.WechatAdsAgencyTokenInterceptor( Interceptors.Add(new Interceptors.WechatAdsRequestAgencyTokenInterceptor(
agencyId: options.AgencyId, agencyId: options.AgencyId,
agencyApiKey: options.AgencyApiKey agencyApiKey: options.AgencyApiKey
)); ));

View File

@ -19,13 +19,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
/// <param name="callbackSignature">微信回调通知中的 Wechatpay-Signature 字段。</param> /// <param name="callbackSignature">微信回调通知中的 Wechatpay-Signature 字段。</param>
/// <param name="callbackSerialNumber">微信回调通知中的 Wechatpay-Serial 字段。</param> /// <param name="callbackSerialNumber">微信回调通知中的 Wechatpay-Serial 字段。</param>
/// <returns></returns> /// <returns></returns>
public static bool VerifyEventSignature( public static bool VerifyEventSignature(this WechatTenpayClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSerialNumber)
this WechatTenpayClient client,
string callbackTimestamp,
string callbackNonce,
string callbackBody,
string callbackSignature,
string callbackSerialNumber)
{ {
return VerifyEventSignature(client, callbackTimestamp, callbackNonce, callbackBody, callbackSignature, callbackSerialNumber, out _); return VerifyEventSignature(client, callbackTimestamp, callbackNonce, callbackBody, callbackSignature, callbackSerialNumber, out _);
} }
@ -44,14 +38,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
/// <param name="error"></param> /// <param name="error"></param>
/// <returns></returns> /// <returns></returns>
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentNullException"></exception>
public static bool VerifyEventSignature( public static bool VerifyEventSignature(this WechatTenpayClient client, string callbackTimestamp, string callbackNonce, string callbackBody, string callbackSignature, string callbackSerialNumber, out Exception? error)
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 (client == null) throw new ArgumentNullException(nameof(client));
if (callbackTimestamp == null) throw new ArgumentNullException(nameof(callbackTimestamp)); if (callbackTimestamp == null) throw new ArgumentNullException(nameof(callbackTimestamp));

View File

@ -40,11 +40,55 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
if (client == null) throw new ArgumentNullException(nameof(client)); if (client == null) throw new ArgumentNullException(nameof(client));
if (response == null) throw new ArgumentNullException(nameof(response)); 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);
}
/// <summary>
/// <para>验证响应签名。</para>
/// <para>REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml </para>
/// <para>REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_1.shtml </para>
/// </summary>
/// <param name="client"></param>
/// <param name="responseTimestamp"></param>
/// <param name="responseNonce">。</param>
/// <param name="responseBody"></param>
/// <param name="responseSignature"></param>
/// <param name="responseSerialNumber"></param>
/// <returns></returns>
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 _);
}
/// <summary>
/// <para>验证响应签名。</para>
/// <para>REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml </para>
/// <para>REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_1.shtml </para>
/// </summary>
/// <typeparam name="TResponse"></typeparam>
/// <param name="client"></param>
/// <param name="responseTimestamp"></param>
/// <param name="responseNonce">。</param>
/// <param name="responseBody"></param>
/// <param name="responseSignature"></param>
/// <param name="responseSerialNumber"></param>
/// <param name="error"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
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) if (client.PlatformCertificateManager != null)
{ {
try try
{ {
var cert = client.PlatformCertificateManager.GetEntry(response.WechatpayCertificateSerialNumber)!; var cert = client.PlatformCertificateManager.GetEntry(responseSerialNumber)!;
if (!cert.HasValue) if (!cert.HasValue)
{ {
error = new Exceptions.WechatTenpayResponseVerificationException("Verify signature of response failed, because there is no platform certificate matched the serial number."); 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; error = null;
return Utilities.RSAUtility.VerifyWithSHA256ByCertificate( return Utilities.RSAUtility.VerifyWithSHA256ByCertificate(
certificate: cert.Value.Certificate, certificate: cert.Value.Certificate,
plainText: GetPlainTextForSignature(response), plainText: GetPlainTextForSignature(timestamp: responseTimestamp, nonce: responseNonce, body: responseBody),
signature: response.WechatpaySignature signature: responseSignature
); );
} }
catch (Exception ex) catch (Exception ex)
@ -69,11 +113,8 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
return false; 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"; return $"{timestamp}\n{nonce}\n{body}\n";
} }
} }

View File

@ -6,14 +6,14 @@ using Flurl.Http;
namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Interceptors namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Interceptors
{ {
internal class WechatTenpaySignInterceptor : FlurlHttpCallInterceptor internal class WechatTenpayRequestSignatureInterceptor : FlurlHttpCallInterceptor
{ {
private readonly string _scheme; private readonly string _scheme;
private readonly string _mchId; private readonly string _mchId;
private readonly string _mchCertSn; private readonly string _mchCertSn;
private readonly string _mchCertPk; 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; _scheme = scheme;
_mchId = mchId; _mchId = mchId;
@ -24,6 +24,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Interceptors
public override async Task BeforeCallAsync(FlurlCall flurlCall) public override async Task BeforeCallAsync(FlurlCall flurlCall)
{ {
if (flurlCall == null) throw new ArgumentNullException(nameof(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 method = flurlCall.HttpRequestMessage.Method.ToString().ToUpper();
string url = flurlCall.HttpRequestMessage.RequestUri?.PathAndQuery ?? string.Empty; 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}\""; string auth = $"mchid=\"{_mchId}\",nonce_str=\"{nonce}\",signature=\"{signText}\",timestamp=\"{timestamp}\",serial_no=\"{_mchCertSn}\"";
flurlCall.Request.Headers.Remove("Authorization"); flurlCall.Request.Headers.Remove(Contants.HttpHeaders.Authorization);
flurlCall.Request.WithHeader("Authorization", $"{_scheme} {auth}"); flurlCall.Request.WithHeader(Contants.HttpHeaders.Authorization, $"{_scheme} {auth}");
} }
} }
} }

View File

@ -55,7 +55,7 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
FlurlClient.WithHeader(Contants.HttpHeaders.UserAgent, options.UserAgent); FlurlClient.WithHeader(Contants.HttpHeaders.UserAgent, options.UserAgent);
FlurlClient.WithTimeout(TimeSpan.FromMilliseconds(options.Timeout)); FlurlClient.WithTimeout(TimeSpan.FromMilliseconds(options.Timeout));
Interceptors.Add(new Interceptors.WechatTenpaySignInterceptor( Interceptors.Add(new Interceptors.WechatTenpayRequestSignatureInterceptor(
scheme: options.SignAlgorithm, scheme: options.SignAlgorithm,
mchId: options.MerchantId, mchId: options.MerchantId,
mchCertSn: options.MerchantCertificateSerialNumber, mchCertSn: options.MerchantCertificateSerialNumber,