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<IOptionsMonitor<WxPayOption>>().CurrentValue;
|
|
protected IHttpClientFactory HttpClientFactory => LazyServiceProvider.LazyGetRequiredService<IHttpClientFactory>();
|
|
protected WxPayRsaHelper WxPayRsaHelper => LazyServiceProvider.LazyGetRequiredService<WxPayRsaHelper>();
|
|
public async Task<TResult> PostAsync<TInput, TResult>(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<TResult>(str);
|
return result;
|
}
|
|
public async Task<TResult> GetAsync<TInput, TResult>(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<TResult>(str);
|
var requestBody = JsonConvert.SerializeObject(input);
|
return result;
|
}
|
|
public async Task<TResult> Certificates<TResult>(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<TResult>(str);
|
return result;
|
}
|
|
public async Task<CertificatesReponse> GetCertificates()
|
{
|
return await Certificates<CertificatesReponse>(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}\"";
|
}
|
|
|
|
}
|
}
|