using System; using System.Text; namespace SKIT.FlurlHttpClient.Wechat.TenpayV3 { /// /// 为 提供响应签名验证的扩展方法。 /// public static class WechatTenpayClientResponseVerificationExtensions { /// /// 验证响应签名。 /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_1.shtml /// /// /// /// /// public static bool VerifyResponseSignature(this WechatTenpayClient client, TResponse response) where TResponse : WechatTenpayResponse { return VerifyResponseSignature(client, response, out _); } /// /// 验证响应签名。 /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml /// REF: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_1.shtml /// /// /// /// /// /// /// public static bool VerifyResponseSignature(this WechatTenpayClient client, TResponse response, out Exception? error) where TResponse : WechatTenpayResponse { if (client == null) throw new ArgumentNullException(nameof(client)); if (response == null) throw new ArgumentNullException(nameof(response)); if (client.CertificateManager != null) { try { var cert = client.CertificateManager.GetEntry(response.WechatpayCertSerialNumber)!; if (!cert.HasValue) { error = new Exceptions.WechatTenpayResponseVerificationException("Verify signature of response failed, because there is no platform certificate matched the serial number."); return false; } error = null; return Utilities.RSAUtility.VerifyWithSHA256ByCertificate( certificate: cert.Value.Certificate, plainText: GetPlainTextForSignature(response), signature: response.WechatpaySignature ); } catch (Exception ex) { error = new Exceptions.WechatTenpayResponseVerificationException("Verify signature of response failed. Please see the `InnerException` for more details.", ex); return false; } } error = new Exceptions.WechatTenpayResponseVerificationException("Verify signature of response failed, because there is no platform certificate in the manager."); return false; } private static string GetPlainTextForSignature(WechatTenpayResponse response) { string timestamp = response.WechatpayTimestamp; string nonce = response.WechatpayNonce; string body = Encoding.UTF8.GetString(response.RawBytes); return $"{timestamp}\n{nonce}\n{body}\n"; } } }