WeChatPayBackgroundService.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using System.Security.Cryptography.X509Certificates;
  2. using Essensoft.Paylinks.WeChatPay.Certificates.Extensions;
  3. using Essensoft.Paylinks.WeChatPay.Certificates.Request;
  4. using Essensoft.Paylinks.WeChatPay.Client;
  5. using Essensoft.Paylinks.WeChatPay.Core.Utilities;
  6. using Microsoft.Extensions.Options;
  7. namespace Essensoft.Paylinks.Sample.Web.Services;
  8. /// <summary>
  9. /// 微信支付后台服务
  10. /// 定时更新微信支付平台证书(12小时)。
  11. /// </summary>
  12. public class WeChatPayBackgroundService(
  13. ILogger<WeChatPayBackgroundService> logger,
  14. IWeChatPayClient client,
  15. IWeChatPayPlatformCertificateManagerFactory certificateManagerFactory,
  16. IOptions<PaylinksOptions> options) : BackgroundService
  17. {
  18. private readonly PaylinksOptions _options = options.Value;
  19. // 如何通过证书信任链验证平台证书?https://pay.weixin.qq.com/doc/v3/merchant/4012072597
  20. // 微信支付平台证书信任链: https://wx.gtimg.com/mch/files/CertTrustChain.p7b
  21. private const string WeChatPayRootCertPem = """
  22. subject=/C=CN/O=Tenpay.com/OU=Tenpay.com CA Center/CN=Tenpay.com Root CA
  23. issuer=/C=CN/O=iTrusChina/OU=China Trust Network/CN=iTrusChina Class 2 Enterprise CA - G3
  24. -----BEGIN CERTIFICATE-----
  25. MIIEcDCCA1igAwIBAgIUG9QiDlDbwEsGrTl1SYRsAcPo69IwDQYJKoZIhvcNAQEL
  26. BQAwcDELMAkGA1UEBhMCQ04xEzARBgNVBAoMCmlUcnVzQ2hpbmExHDAaBgNVBAsM
  27. E0NoaW5hIFRydXN0IE5ldHdvcmsxLjAsBgNVBAMMJWlUcnVzQ2hpbmEgQ2xhc3Mg
  28. MiBFbnRlcnByaXNlIENBIC0gRzMwHhcNMTcwODA5MDkxNTU1WhcNMzIwODA5MDkx
  29. NTU1WjBeMQswCQYDVQQGEwJDTjETMBEGA1UEChMKVGVucGF5LmNvbTEdMBsGA1UE
  30. CxMUVGVucGF5LmNvbSBDQSBDZW50ZXIxGzAZBgNVBAMTElRlbnBheS5jb20gUm9v
  31. dCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALvnPD6k39BdPYAH
  32. +6lnWPjuHH+2pcmZUf2E8cNFQFNr+ECRZylYV2iKyItCQt3I2/7VIDZl6aR9TE7n
  33. sZrtSmOXCw635QOrq2yF9LTSDotAhf3ER0+216w3age/VzGcNVQpTf6gRCHCuQIk
  34. 8pe/oh06JagGvX0wERa+I6NfuG58ZHQY9d6RqLXKQl0Up95v73HDsG487z8k6jcn
  35. qpGngmHQxdWiWRJugqxNRUD+awv2/DUsqGOffPX4jzJ6rLSJSlQXvuniDYxmaiaD
  36. cK0bUbB5aM+1zMwogoHSYxWj/6B+vgcnHQCUrwGdiQR5+F+yRWzy5bO09IzaFgeO
  37. PNPLPOsCAwEAAaOCARIwggEOMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/
  38. BAQDAgEGMCAGA1UdEQQZMBekFTATMREwDwYDVQQDDAhzd2JlLTI2NjAdBgNVHQ4E
  39. FgQUTFo4GLdm9oHX52HcWnzuL4tui2gwHwYDVR0jBBgwFoAUK1vVxWgI69vN5LA5
  40. MqJf/8dPmEUwRgYDVR0gBD8wPTA7BgoqgRyG7xcBAQECMC0wKwYIKwYBBQUHAgEW
  41. H2h0dHBzOi8vd3d3Lml0cnVzLmNvbS5jbi9jdG5jcHMwPgYDVR0fBDcwNTAzoDGg
  42. L4YtaHR0cDovL3RvcGNhLml0cnVzLmNvbS5jbi9jcmwvaXRydXNjMmNhZzMuY3Js
  43. MA0GCSqGSIb3DQEBCwUAA4IBAQBwZhL/eiOQmMyo1D0IR9mu1DPWl5J3XXhjc4R6
  44. mFgsN/FCeVP9M4U9y2FJH6i5Ha5YCecKGw5pwhA0rjZr/6okWwo22GF+nzI/gQiz
  45. 6ugAKs5VjFbeiEb04Ncz4HT8FP1idK3tyCjqCUTkLNt0U3tR7wy26hgOqlT2wCZ9
  46. X4MfT8dUMdt9nCZx4ujN5yZOzaLOCHmzoGDGxgKg91bbu0TG2Yzd2ylhrxxRtFH9
  47. aZ/J1x5UoF7uwhTM8P92DuAldWC1/bX1kciOtQvQEZeAy+9y/1BtFxoBnmDxnqkX
  48. +lirIUYTLDaL7HaLrOLECUlaxZCU/Nkwm3tmqQxtCh+XQBdd
  49. -----END CERTIFICATE-----
  50. subject=/C=CN/O=iTrusChina/OU=China Trust Network/CN=iTrusChina Class 2 Root CA - G3
  51. issuer=/C=CN/O=iTrusChina/OU=China Trust Network/CN=iTrusChina Class 2 Root CA - G3
  52. -----BEGIN CERTIFICATE-----
  53. MIIDxTCCAq2gAwIBAgIUEMdk6dVgOEIS2cCP0Q43P90Ps5YwDQYJKoZIhvcNAQEF
  54. BQAwajELMAkGA1UEBhMCQ04xEzARBgNVBAoMCmlUcnVzQ2hpbmExHDAaBgNVBAsM
  55. E0NoaW5hIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMMH2lUcnVzQ2hpbmEgQ2xhc3Mg
  56. MiBSb290IENBIC0gRzMwHhcNMTMwNDE4MDkzNjU2WhcNMzMwNDE4MDkzNjU2WjBq
  57. MQswCQYDVQQGEwJDTjETMBEGA1UECgwKaVRydXNDaGluYTEcMBoGA1UECwwTQ2hp
  58. bmEgVHJ1c3QgTmV0d29yazEoMCYGA1UEAwwfaVRydXNDaGluYSBDbGFzcyAyIFJv
  59. b3QgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPPShpV
  60. nJbMqqCw6Bz1kehnoPst9pkr0V9idOwU2oyS47/HjJXk9Rd5a9xfwkPO88trUpz5
  61. 4GmmwspDXjVFu9L0eFaRuH3KMha1Ak01citbF7cQLJlS7XI+tpkTGHEY5pt3EsQg
  62. wykfZl/A1jrnSkspMS997r2Gim54cwz+mTMgDRhZsKK/lbOeBPpWtcFizjXYCqhw
  63. WktvQfZBYi6o4sHCshnOswi4yV1p+LuFcQ2ciYdWvULh1eZhLxHbGXyznYHi0dGN
  64. z+I9H8aXxqAQfHVhbdHNzi77hCxFjOy+hHrGsyzjrd2swVQ2iUWP8BfEQqGLqM1g
  65. KgWKYfcTGdbPB1MCAwEAAaNjMGEwHQYDVR0OBBYEFG/oAMxTVe7y0+408CTAK8hA
  66. uTyRMB8GA1UdIwQYMBaAFG/oAMxTVe7y0+408CTAK8hAuTyRMA8GA1UdEwEB/wQF
  67. MAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBLnUTfW7hp
  68. emMbuUGCk7RBswzOT83bDM6824EkUnf+X0iKS95SUNGeeSWK2o/3ALJo5hi7GZr3
  69. U8eLaWAcYizfO99UXMRBPw5PRR+gXGEronGUugLpxsjuynoLQu8GQAeysSXKbN1I
  70. UugDo9u8igJORYA+5ms0s5sCUySqbQ2R5z/GoceyI9LdxIVa1RjVX8pYOj8JFwtn
  71. DJN3ftSFvNMYwRuILKuqUYSHc2GPYiHVflDh5nDymCMOQFcFG3WsEuB+EYQPFgIU
  72. 1DHmdZcz7Llx8UOZXX2JupWCYzK1XhJb+r4hK5ncf/w8qGtYlmyJpxk3hr1TfUJX
  73. Yf4Zr0fJsGuv
  74. -----END CERTIFICATE-----
  75. subject=/C=CN/O=iTrusChina/OU=China Trust Network/CN=iTrusChina Class 2 Enterprise CA - G3
  76. issuer=/C=CN/O=iTrusChina/OU=China Trust Network/CN=iTrusChina Class 2 Root CA - G3
  77. -----BEGIN CERTIFICATE-----
  78. MIIEWzCCA0OgAwIBAgIUXebgKKreiIUWpld7APPGQeaeEzEwDQYJKoZIhvcNAQEF
  79. BQAwajELMAkGA1UEBhMCQ04xEzARBgNVBAoMCmlUcnVzQ2hpbmExHDAaBgNVBAsM
  80. E0NoaW5hIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMMH2lUcnVzQ2hpbmEgQ2xhc3Mg
  81. MiBSb290IENBIC0gRzMwHhcNMTMwNDE4MDk0NDE3WhcNMzMwNDE3MDk0NDE3WjBw
  82. MQswCQYDVQQGEwJDTjETMBEGA1UECgwKaVRydXNDaGluYTEcMBoGA1UECwwTQ2hp
  83. bmEgVHJ1c3QgTmV0d29yazEuMCwGA1UEAwwlaVRydXNDaGluYSBDbGFzcyAyIEVu
  84. dGVycHJpc2UgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
  85. AL2hymJqz9ASXoYSuCCNZi4/q/FWnOcnNkk0jgDTmwsXa+vr6f/c2gbRAehBu1Uh
  86. 1m9N/yp4Enxzf5EPh1yTTQ7042PJfh8I5x+I6A64xYN4qGPlYnl8gmP/0+fTDejJ
  87. vPtM59k83rhGQsZzyp9rMiaUphHbFEr6ZWWrCg1SADP6NlP3P90wOmBviE12yGsv
  88. JZF1HOaTSKuSWDGZPZq8RO+q9lfhlOHi0Ht7V+hnuxCOgN/PWhvoh0KpHhPi0OKn
  89. 6/RIZObZqMBqngPEUHXZfkzIQo6KEUvvWduvOC6P5hPpbAr0+xvE2WFORyRyL52W
  90. 8bfkc8/QzdxxCa9RVpzRuFcCAwEAAaOB8jCB7zAPBgNVHRMBAf8EBTADAQH/MA4G
  91. A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUK1vVxWgI69vN5LA5MqJf/8dPmEUwHwYD
  92. VR0jBBgwFoAUb+gAzFNV7vLT7jTwJMAryEC5PJEwRgYDVR0gBD8wPTA7BgoqgRyG
  93. 7xcBAQECMC0wKwYIKwYBBQUHAgEWH2h0dHBzOi8vd3d3Lml0cnVzLmNvbS5jbi9j
  94. dG5jcHMwRAYDVR0fBD0wOzA5oDegNYYzaHR0cDovL2ljYS1wdWJsaWMuaXRydXMu
  95. Y29tLmNuL2NybC9pdHJ1c2MycmNhZzMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQA3
  96. WmfVeOre6edXZmsq1RXYAoJf/is70tRqJKato6KpOHkmGmo/+btAJ9JqKYSciOoq
  97. 7OkAuQugkA9BoMLZkaGhvPIYuRqQmDcpLEvVS5L5acKKlQiRmyLKXtmZmBUP0Dxd
  98. SAbF9CG45abr226WQ9Yx+I5RjW0BMDZUBOHL+x8oOy3Sw5aqWznbPyNbCKFtJ0pV
  99. n0rx0BtfpRdnuew0cshfNOGn05N7W5YmYD1S6gbVQt5VZL9fAXphYlM12rlSaDiB
  100. NdM0hSb43laYFyH9bnMJxZDqcEQ/YwZZ0nfRfvRXx+s/8kvHmZPgmx9sGGfCx2AZ
  101. RCQzBAe4s75o8F08GgkU
  102. -----END CERTIFICATE-----
  103. """;
  104. protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  105. {
  106. var certTrustChain = new X509Certificate2Collection();
  107. certTrustChain.ImportFromPem(WeChatPayRootCertPem);
  108. while (!stoppingToken.IsCancellationRequested)
  109. {
  110. if (!string.IsNullOrEmpty(_options.WeChatPay.WeChatPayPublicKeyId) && !string.IsNullOrEmpty(_options.WeChatPay.WeChatPayPublicKey))
  111. {
  112. logger.LogInformation("微信支付后台服务取消:已配置微信支付公钥,无需下载平台证书。");
  113. break;
  114. }
  115. if (string.IsNullOrEmpty(_options.WeChatPay.MchId) ||
  116. string.IsNullOrEmpty(_options.WeChatPay.MchSerialNo) ||
  117. string.IsNullOrEmpty(_options.WeChatPay.MchPrivateKey))
  118. {
  119. logger.LogWarning("微信支付后台服务取消:未配置微信支付下载平台证书关键参数。");
  120. break;
  121. }
  122. try
  123. {
  124. var certificateManager = certificateManagerFactory.Create(_options.WeChatPay.MchId);
  125. // 移除所有无效证书
  126. certificateManager.RemoveUnavailableCertificates();
  127. // 下载平台证书请求
  128. var request = new WeChatPayCertificatesRequest();
  129. // 无有效平台证书时,不需要验签。
  130. if (!certificateManager.GetAvailableCertificates().Any())
  131. {
  132. request.SetNeedVerify(false);
  133. }
  134. // 执行请求
  135. var response = await client.ExecuteAsync(request, _options.WeChatPay, stoppingToken);
  136. if (response.IsSuccessful)
  137. {
  138. // 获取解密后的平台证书
  139. foreach (var certificate in response.GetWeChatPayDecryptedPlatformCertificates(_options.WeChatPay.APIv3Key))
  140. {
  141. // 跳过已存在的证书
  142. if (certificateManager.GetBySerialNo(certificate.SerialNo) != null)
  143. {
  144. continue;
  145. }
  146. // 证书信任链验证平台证书
  147. if (WeChatPayCertUtilities.VerifyCertificateChain(certTrustChain, certificate.Certificate))
  148. {
  149. certificateManager.Add(certificate);
  150. logger.LogInformation($"新增微信平台证书: {certificate.SerialNo}");
  151. }
  152. }
  153. }
  154. else
  155. {
  156. logger.LogError(response.Body);
  157. }
  158. }
  159. catch (Exception ex)
  160. {
  161. logger.LogError(ex.Message);
  162. }
  163. await Task.Delay(TimeSpan.FromHours(12), stoppingToken);
  164. }
  165. }
  166. }