using System.Security.Cryptography;
using System.Threading.Tasks;
namespace HttpHandlerDemo
// HttpClient client = new HttpClient(new HttpHandler("{商户号}", "{商户证书序列号}"));
// var response = client.GetAsync("https://api.mch.weixin.qq.com/v3/certificates");
public class HttpHandler : DelegatingHandler
private readonly string merchantId;
private readonly string serialNo;
public HttpHandler(string merchantId, string merchantSerialNo)
InnerHandler = new HttpClientHandler();
this.merchantId = merchantId;
this.serialNo = merchantSerialNo;
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
var auth = await BuildAuthAsync(request);
string value = quot;WECHATPAY2-SHA256-RSA2048 {auth}";
request.Headers.Add("Authorization", value);
return await base.SendAsync(request, cancellationToken);
protected async Task<string> BuildAuthAsync(HttpRequestMessage request)
string method = request.Method.ToString();
if (method == "POST" || method == "PUT" || method == "PATCH")
var content = request.Content;
body = await content.ReadAsStringAsync();
string uri = request.RequestUri.PathAndQuery;
var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
string nonce = Path.GetRandomFileName();
string message = quot;{method}\n{uri}\n{timestamp}\n{nonce}\n{body}\n";
string signature = Sign(message);
return quot;mchid=\"{merchantId}\",nonce_str=\"{nonce}\",timestamp=\"{timestamp}\",serial_no=\"{serialNo}\",signature=\"{signature}\"";
protected string Sign(string message)
// NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY-----
// 亦不包括结尾的-----END PRIVATE KEY-----
string privateKey = "{你的私钥}";
byte[] keyData = Convert.FromBase64String(privateKey);
rsa.ImportPkcs8PrivateKey(keyData, out _);
byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));