From 36a799cbcb02331797c08704972701442821f667 Mon Sep 17 00:00:00 2001 From: real-zony Date: Sun, 7 Jan 2024 20:41:55 +0800 Subject: [PATCH 1/2] refactor: Adjusted the signature generation method to create signatures for JS payment (V3). --- .../Dtos/GetJsSdkWeChatPayParametersInput.cs | 2 ++ .../Security/CertificatesManager.cs | 11 +++++++++++ .../Security/ICertificatesManager.cs | 8 ++++++++ .../WeChatPayAuthorizationGenerator.cs | 18 +++--------------- .../Security/WeChatPayCertificate.cs | 2 +- 5 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay.Abstractions/RequestHandling/Dtos/GetJsSdkWeChatPayParametersInput.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay.Abstractions/RequestHandling/Dtos/GetJsSdkWeChatPayParametersInput.cs index e90a751..578c009 100644 --- a/src/Pay/EasyAbp.Abp.WeChat.Pay.Abstractions/RequestHandling/Dtos/GetJsSdkWeChatPayParametersInput.cs +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay.Abstractions/RequestHandling/Dtos/GetJsSdkWeChatPayParametersInput.cs @@ -1,11 +1,13 @@ using System; using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; namespace EasyAbp.Abp.WeChat.Pay.RequestHandling.Dtos; [Serializable] public class GetJsSdkWeChatPayParametersInput { + [CanBeNull] public string MchId { get; set; } [Required] diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/CertificatesManager.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/CertificatesManager.cs index d7bd59f..45495bc 100644 --- a/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/CertificatesManager.cs +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/CertificatesManager.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Concurrent; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; using System.Threading.Tasks; using EasyAbp.Abp.WeChat.Pay.Options; using Volo.Abp.BlobStoring; @@ -36,6 +39,14 @@ public async Task GetCertificateAsync(string mchId) new WeChatPayCertificate(options.MchId, certificateBytes, options.CertificateSecret))).Value; } + public string GetSignature(string pendingSignature, WeChatPayCertificate certificate) + { + var privateKey = certificate.X509Certificate.GetRSAPrivateKey(); + var signDataBytes = privateKey.SignData(Encoding.UTF8.GetBytes(pendingSignature), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + + return Convert.ToBase64String(signDataBytes); + } + protected virtual async Task GetX509CertificateBytesAsync(AbpWeChatPayOptions options) { if (options.CertificateBlobName.IsNullOrEmpty()) diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/ICertificatesManager.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/ICertificatesManager.cs index 4346b02..ed3e3a2 100644 --- a/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/ICertificatesManager.cs +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/ICertificatesManager.cs @@ -16,4 +16,12 @@ public interface ICertificatesManager /// 当证书的 BLOB 不存在时抛出此异常。 /// 无法获取证书时会抛出此异常。 Task GetCertificateAsync(string mchId); + + /// + /// 使用微信支付证书对待签名字符串进行签名。 + /// + /// 等待签名的字符串。 + /// 用于签名的证书实例。 + /// 具体的签名数据,使用 Base64 编码。 + string GetSignature(string pendingSignature, WeChatPayCertificate certificate); } \ No newline at end of file diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/WeChatPayAuthorizationGenerator.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/WeChatPayAuthorizationGenerator.cs index cde9743..ee75893 100644 --- a/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/WeChatPayAuthorizationGenerator.cs +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/WeChatPayAuthorizationGenerator.cs @@ -1,8 +1,4 @@ -using System; -using System.Net.Http; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using System.Text; +using System.Net.Http; using System.Threading.Tasks; using EasyAbp.Abp.WeChat.Common.Extensions; using EasyAbp.Abp.WeChat.Pay.ApiRequests; @@ -21,7 +17,7 @@ public class WeChatPayAuthorizationGenerator : IWeChatPayAuthorizationGenerator, /// 授权(Authorization)标头的认证类型。 /// public const string AuthorizationScheme = "WECHATPAY2-SHA256-RSA2048"; - + private readonly IAbpWeChatPayOptionsProvider _weChatPayOptionsProvider; private readonly ICertificatesManager _certificatesManager; @@ -41,17 +37,9 @@ public async Task GenerateAuthorizationAsync(HttpMethod method, string u var requestModel = new WeChatPayApiRequestModel(method, url, body, timeStamp, nonceStr); var pendingSignature = requestModel.GetPendingSignatureString(); var certificate = await _certificatesManager.GetCertificateAsync(mchId); - var signString = RsaSign(pendingSignature, certificate); + var signString = _certificatesManager.GetSignature(pendingSignature, certificate); return $"{AuthorizationScheme} mchid=\"{options.MchId}\",nonce_str=\"{nonceStr}\",timestamp=\"{timeStamp}\",serial_no=\"{certificate.X509Certificate.SerialNumber}\",signature=\"{signString}\""; } - - private string RsaSign(string pendingSignature, WeChatPayCertificate certificate) - { - var privateKey = certificate.X509Certificate.GetRSAPrivateKey(); - var signDataBytes = privateKey.SignData(Encoding.UTF8.GetBytes(pendingSignature), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); - - return Convert.ToBase64String(signDataBytes); - } } \ No newline at end of file diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/WeChatPayCertificate.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/WeChatPayCertificate.cs index 0430071..56fe601 100644 --- a/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/WeChatPayCertificate.cs +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay/Security/WeChatPayCertificate.cs @@ -28,7 +28,7 @@ public sealed class WeChatPayCertificate /// /// 商户号。 /// X509 证书实例。 - /// X509 证书的哈希值,用于快速比对证书是否发生变化。 + /// X509 证书的密码。 public WeChatPayCertificate(string mchId, byte[] certificateBytes, string password) { MchId = mchId; From 210eeb923f17fa37a47b32e269be152bc20fe2c7 Mon Sep 17 00:00:00 2001 From: real-zony Date: Sun, 7 Jan 2024 20:52:51 +0800 Subject: [PATCH 2/2] feat: Added a new JS API signature method. (V3) --- .../WeChatPayClientRequestHandlingService.cs | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/WeChatPayClientRequestHandlingService.cs b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/WeChatPayClientRequestHandlingService.cs index 22476a1..980f925 100644 --- a/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/WeChatPayClientRequestHandlingService.cs +++ b/src/Pay/EasyAbp.Abp.WeChat.Pay/RequestHandling/WeChatPayClientRequestHandlingService.cs @@ -1,25 +1,23 @@ -using System.Security.Cryptography; +using System.Text; using System.Threading.Tasks; using EasyAbp.Abp.WeChat.Common.Extensions; -using EasyAbp.Abp.WeChat.Common.Infrastructure; -using EasyAbp.Abp.WeChat.Common.Infrastructure.Signature; using EasyAbp.Abp.WeChat.Pay.Options; using EasyAbp.Abp.WeChat.Pay.RequestHandling.Dtos; +using EasyAbp.Abp.WeChat.Pay.Security; using Volo.Abp.DependencyInjection; namespace EasyAbp.Abp.WeChat.Pay.RequestHandling; public class WeChatPayClientRequestHandlingService : IWeChatPayClientRequestHandlingService, ITransientDependency { + private readonly ICertificatesManager _certificatesManager; private readonly IAbpWeChatPayOptionsProvider _optionsProvider; - private readonly ISignatureGenerator _signatureGenerator; - public WeChatPayClientRequestHandlingService( - IAbpWeChatPayOptionsProvider optionsProvider, - ISignatureGenerator signatureGenerator) + public WeChatPayClientRequestHandlingService(ICertificatesManager certificatesManager, + IAbpWeChatPayOptionsProvider optionsProvider) { + _certificatesManager = certificatesManager; _optionsProvider = optionsProvider; - _signatureGenerator = signatureGenerator; } public virtual async Task GetJsSdkWeChatPayParametersAsync( @@ -32,20 +30,18 @@ public virtual async Task GetJsSdkWeChatPayPa var options = await _optionsProvider.GetAsync(input.MchId); + const string signType = "RSA"; var nonceStr = RandomStringHelper.GetRandomString(); var timeStamp = DateTimeHelper.GetNowTimeStamp(); var package = $"prepay_id={input.PrepayId}"; - const string signType = "MD5"; - - var @params = new WeChatParameters(); - @params.AddParameter("appId", input.AppId); - @params.AddParameter("nonceStr", nonceStr); - @params.AddParameter("timeStamp", timeStamp); - @params.AddParameter("package", package); - @params.AddParameter("signType", signType); - - var paySign = _signatureGenerator.Generate(@params, MD5.Create(), options.ApiV3Key); + var waitSignString = new StringBuilder(); + waitSignString.Append(input.AppId).Append('\n') + .Append(timeStamp).Append('\n') + .Append(nonceStr).Append('\n') + .Append("prepay_id=").Append(input.PrepayId).Append('\n'); + var certificate = await _certificatesManager.GetCertificateAsync(options.MchId); + var paySign = _certificatesManager.GetSignature(waitSignString.ToString(), certificate); return new GetJsSdkWeChatPayParametersResult(nonceStr, timeStamp, package, signType, paySign); }