extern alias BouncyCastleA; using LifePayment.Domain.Shared; using Microsoft.Extensions.Options; using Newtonsoft.Json; using System; using System.IO; using System.Linq; using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using AeadParametersA = BouncyCastleA.Org.BouncyCastle.Crypto.Parameters.AeadParameters; using AesEngineA = BouncyCastleA.Org.BouncyCastle.Crypto.Engines.AesEngine; using GcmBlockCipherA = BouncyCastleA.Org.BouncyCastle.Crypto.Modes.GcmBlockCipher; using KeyParameterA = BouncyCastleA.Org.BouncyCastle.Crypto.Parameters.KeyParameter; namespace LifePayment.Domain { public abstract class WxClient { public IAbpLazyServiceProvider LazyServiceProvider { get; set; } protected WxPayOption Options => LazyServiceProvider.LazyGetRequiredService>().CurrentValue; protected IHttpClientFactory HttpClientFactory => LazyServiceProvider.LazyGetRequiredService(); protected WxPayRsaHelper WxPayRsaHelper => LazyServiceProvider.LazyGetRequiredService(); public async Task PostAsync(TInput input, string function) where TInput : WxPayPostBaseModel { var client = HttpClientFactory.CreateClient(LifePaymentConstant.WxPayHttpClientName); var body = JsonConvert.SerializeObject(input); AddAuthHeader(client, BuildAuth(body, function)); var data = new StringContent(body, Encoding.UTF8, "application/json"); var responseMessage = await client.PostAsync($"{Options.Url}{function}", data); var str = await responseMessage.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject(str); return result; } public async Task GetAsync(TInput input, string function) { var client = HttpClientFactory.CreateClient(LifePaymentConstant.WxPayHttpClientName); StringBuilder strBuilder = new StringBuilder(); var type = typeof(TInput); strBuilder.Append(function); var props = type.GetProperties().ToList(); props.Where(r => r.GetCustomAttributes(typeof(PathAttribute), true).Any()).ToList().ForEach(r => { var name = r.Name; var propAttr = (JsonPropertyAttribute)r.GetCustomAttributes(typeof(JsonPropertyAttribute), true).FirstOrDefault(); if (propAttr != null) { name = propAttr.PropertyName; } var value = r.GetValue(input)?.ToString(); if (!value.IsNullOrEmpty()) { strBuilder.Append($"/{name}/{value}"); } }); int i = 0; props.Where(r => r.GetCustomAttributes(typeof(QueryAttribute), true).Any()).ToList().ForEach(r => { if (i == 0) { strBuilder.Append("?"); } else { strBuilder.Append("&"); } var value = r.GetValue(input)?.ToString(); var name = r.Name; var propAttr = (JsonPropertyAttribute)r.GetCustomAttributes(typeof(JsonPropertyAttribute), true).FirstOrDefault(); if (propAttr != null) { name = propAttr.PropertyName; } if (!value.IsNullOrEmpty()) { strBuilder.Append($"{name}={value}"); } i = i + 1; }); AddAuthHeader(client, BuildAuth(string.Empty, strBuilder.ToString(), "GET")); var responseMessage = await client.GetAsync(Options.Url + strBuilder.ToString()); var str = await responseMessage.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject(str); var requestBody = JsonConvert.SerializeObject(input); return result; } public async Task Certificates(string function) { var client = HttpClientFactory.CreateClient(LifePaymentConstant.WxPayHttpClientName); StringBuilder strBuilder = new StringBuilder(); strBuilder.Append(function); AddAuthHeader(client, BuildAuth(string.Empty, strBuilder.ToString(), "GET")); var responseMessage = await client.GetAsync(Options.Url + strBuilder.ToString()); var str = await responseMessage.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject(str); return result; } public async Task GetCertificates() { return await Certificates(LifePaymentConstant.WxPayCertificates); } public string AesGcmDecrypt(string associatedData, string nonce, string ciphertext) { GcmBlockCipherA gcmBlockCipher = new GcmBlockCipherA(new AesEngineA()); AeadParametersA aeadParameters = new AeadParametersA(new KeyParameterA(Encoding.UTF8.GetBytes(Options.APIKey)), 128, Encoding.UTF8.GetBytes(nonce), Encoding.UTF8.GetBytes(associatedData)); gcmBlockCipher.Init(false, aeadParameters); byte[] data = Convert.FromBase64String(ciphertext); byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)]; int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0); gcmBlockCipher.DoFinal(plaintext, length); return Encoding.UTF8.GetString(plaintext); } public string GeneratePaySignByKey(string message) { return WxPayRsaHelper.Sign(message); } protected void AddAuthHeader(HttpClient client, string authSign) { client.DefaultRequestHeaders.Add("Authorization", $"WECHATPAY2-SHA256-RSA2048 {authSign}"); } private string BuildAuth(string body, string url, string method = "POST") { var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds(); string nonce = Path.GetRandomFileName(); string message = $"{method}\n{url}\n{timestamp}\n{nonce}\n{body}\n"; string signature = WxPayRsaHelper.Sign(message); return $"mchid=\"{Options.Mchid}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{Options.SerialNo}\",signature=\"{signature}\""; } } }