diff --git a/docs/WechatTenpayV3/Basic_ModelDefinition.md b/docs/WechatTenpayV3/Basic_ModelDefinition.md
index 9f919d93..a1881361 100644
--- a/docs/WechatTenpayV3/Basic_ModelDefinition.md
+++ b/docs/WechatTenpayV3/Basic_ModelDefinition.md
@@ -1370,6 +1370,20 @@
- 查询不活跃商户身份核实结果:`GetComplianceInactiveMerchantIdentityVerificationByVerificationId`
+- 扩展工具
+
+ - 电商订单实名校验
+
+ - 实名信息校验:`GetRealNameVerification`
+
+ - 微信点餐订单
+
+ - 点餐订单信息同步:`SyncCateringOrderStatus`
+
+ - 微信寄快递
+
+ - 用户 OpenID 转换:`TransformExpressUserOpenId`
+
- 其他
- 来账识别
@@ -1576,14 +1590,6 @@
- 服务商银行来账查询:`QueryMerchantFundMerchantIncomeRecords`
- - 微信点餐订单
-
- - 点餐订单信息同步:`SyncCateringOrderStatus`
-
- - 微信寄快递
-
- - 用户 OpenID 转换:`TransformExpressUserOpenId`
-
---
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteRealNameExtensions.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteRealNameExtensions.cs
new file mode 100644
index 00000000..883f4b0a
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Extensions/WechatTenpayClientExecuteRealNameExtensions.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Flurl.Http;
+
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3
+{
+ public static class WechatTenpayClientExecuteRealNameExtensions
+ {
+ ///
+ /// 异步调用 [GET] /realname/verify 接口。
+ ///
+ /// REF:
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static async Task ExecuteGetRealNameVerificationAsync(this WechatTenpayClient client, Models.GetRealNameVerificationRequest request, CancellationToken cancellationToken = default)
+ {
+ if (client is null) throw new ArgumentNullException(nameof(client));
+ if (request is null) throw new ArgumentNullException(nameof(request));
+
+ IFlurlRequest flurlReq = client
+ .CreateFlurlRequest(request, HttpMethod.Get, "realname", "verify")
+ .SetQueryParam("credential_type", request.CredentialType)
+ .SetQueryParam("encrypted_credential_id", request.CredentialId)
+ .SetQueryParam("encrypted_name", request.CredentialName)
+ .SetQueryParam("wxp_trade_no", request.TransactionId);
+
+ return await client.SendFlurlRequestAsJsonAsync(flurlReq, data: request, cancellationToken: cancellationToken).ConfigureAwait(false);
+ }
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/_Partner/RealName/GetRealNameVerificationRequest.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/_Partner/RealName/GetRealNameVerificationRequest.cs
new file mode 100644
index 00000000..dfce8946
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/_Partner/RealName/GetRealNameVerificationRequest.cs
@@ -0,0 +1,42 @@
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /realname/verify 接口的请求。
+ ///
+ [WechatTenpaySensitive]
+ public class GetRealNameVerificationRequest : WechatTenpayRequest
+ {
+ ///
+ /// 获取或设置下单用户证件类型。
+ /// 默认值:"1"
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string CredentialType { get; set; } = "1";
+
+ ///
+ /// 获取或设置下单用户证件号(需使用平台公钥/证书加密)。
+ ///
+ [WechatTenpaySensitiveProperty(scheme: Constants.SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256, algorithm: Constants.EncryptionAlgorithms.RSA_2048_ECB_PKCS8_OAEP_WITH_SHA1_AND_MGF1)]
+ [WechatTenpaySensitiveProperty(scheme: Constants.SignSchemes.WECHATPAY2_SM2_WITH_SM3, algorithm: Constants.EncryptionAlgorithms.SM2_C1C3C2_ASN1)]
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string CredentialId { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置下单用户姓名(需使用平台公钥/证书加密)。
+ ///
+ [WechatTenpaySensitiveProperty(scheme: Constants.SignSchemes.WECHATPAY2_RSA_2048_WITH_SHA256, algorithm: Constants.EncryptionAlgorithms.RSA_2048_ECB_PKCS8_OAEP_WITH_SHA1_AND_MGF1)]
+ [WechatTenpaySensitiveProperty(scheme: Constants.SignSchemes.WECHATPAY2_SM2_WITH_SM3, algorithm: Constants.EncryptionAlgorithms.SM2_C1C3C2_ASN1)]
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string CredentialName { get; set; } = string.Empty;
+
+ ///
+ /// 获取或设置微信支付交易单号。
+ ///
+ [Newtonsoft.Json.JsonIgnore]
+ [System.Text.Json.Serialization.JsonIgnore]
+ public string TransactionId { get; set; } = string.Empty;
+ }
+}
diff --git a/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/_Partner/RealName/GetRealNameVerificationResponse.cs b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/_Partner/RealName/GetRealNameVerificationResponse.cs
new file mode 100644
index 00000000..f4aeaf36
--- /dev/null
+++ b/src/SKIT.FlurlHttpClient.Wechat.TenpayV3/Models/_Partner/RealName/GetRealNameVerificationResponse.cs
@@ -0,0 +1,22 @@
+namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.Models
+{
+ ///
+ /// 表示 [GET] /realname/verify 接口的响应。
+ ///
+ public class GetRealNameVerificationResponse : WechatTenpayResponse
+ {
+ ///
+ /// 获取或设置实名比对结果。
+ ///
+ [Newtonsoft.Json.JsonProperty("verify_result")]
+ [System.Text.Json.Serialization.JsonPropertyName("verify_result")]
+ public int VerifyResult { get; set; }
+
+ ///
+ /// 获取或设置实名比对错误信息。
+ ///
+ [Newtonsoft.Json.JsonProperty("err_message")]
+ [System.Text.Json.Serialization.JsonPropertyName("err_message")]
+ public string? VerifyErrorMessage { get; set; }
+ }
+}
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/_/_Partner/RealName/GetRealNameVerificationResponse.json b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/_/_Partner/RealName/GetRealNameVerificationResponse.json
new file mode 100644
index 00000000..485699ba
--- /dev/null
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/ModelSamples/_/_Partner/RealName/GetRealNameVerificationResponse.json
@@ -0,0 +1,4 @@
+{
+ "verify_result": 0,
+ "err_message": "realname verify succ"
+}
diff --git a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_RequestEncryptionTests.cs b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_RequestEncryptionTests.cs
index a436fbf6..47fa7850 100644
--- a/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_RequestEncryptionTests.cs
+++ b/test/SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests/TestCase_RequestEncryptionTests.cs
@@ -1774,6 +1774,62 @@ namespace SKIT.FlurlHttpClient.Wechat.TenpayV3.UnitTests
}
}
+ [Fact(DisplayName = "测试用例:加密请求中的敏感数据([POST] /realname/verify)")]
+ public async Task TestEncryptRequestSensitiveProperty_GetRealNameVerificationRequest()
+ {
+ static Models.GetRealNameVerificationRequest GenerateMockRequestModel()
+ {
+ return new Models.GetRealNameVerificationRequest()
+ {
+ CredentialId = MOCK_PLAIN_STR,
+ CredentialName = MOCK_PLAIN_STR
+ };
+ }
+
+ static void AssertMockRequestModel(Models.GetRealNameVerificationRequest request, Func decryptor)
+ {
+ Assert.NotEqual(MOCK_PLAIN_STR, request.CredentialId);
+ Assert.NotEqual(MOCK_PLAIN_STR, request.CredentialName);
+ Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.CredentialId));
+ Assert.Equal(MOCK_PLAIN_STR, decryptor.Invoke(request.CredentialName));
+ Assert.Equal(MOCK_CERT_SN, request.WechatpaySerialNumber!, ignoreCase: true);
+ }
+
+ if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantRSACertificatePrivateKey))
+ {
+ using (var client = CreateMockClientUseRSA(autoEncrypt: false))
+ {
+ var request = GenerateMockRequestModel();
+ client.EncryptRequestSensitiveProperty(request);
+ AssertMockRequestModel(request, (cipher) => Utilities.RSAUtility.DecryptWithECB(RSA_PEM_PRIVATE_KEY, (EncodedString)cipher)!);
+ }
+
+ using (var client = CreateMockClientUseRSA(autoEncrypt: true))
+ {
+ var request = GenerateMockRequestModel();
+ await client.ExecuteGetRealNameVerificationAsync(request);
+ AssertMockRequestModel(request, (cipher) => Utilities.RSAUtility.DecryptWithECB(RSA_PEM_PRIVATE_KEY, (EncodedString)cipher)!);
+ }
+ }
+
+ if (!string.IsNullOrEmpty(TestConfigs.WechatMerchantSM2CertificatePrivateKey))
+ {
+ using (var client = CreateMockClientUseSM2(autoEncrypt: false))
+ {
+ var request = GenerateMockRequestModel();
+ client.EncryptRequestSensitiveProperty(request);
+ AssertMockRequestModel(request, (cipher) => Utilities.SM2Utility.Decrypt(SM2_PEM_PRIVATE_KEY, (EncodedString)cipher)!);
+ }
+
+ using (var client = CreateMockClientUseSM2(autoEncrypt: true))
+ {
+ var request = GenerateMockRequestModel();
+ await client.ExecuteGetRealNameVerificationAsync(request);
+ AssertMockRequestModel(request, (cipher) => Utilities.SM2Utility.Decrypt(SM2_PEM_PRIVATE_KEY, (EncodedString)cipher)!);
+ }
+ }
+ }
+
[Fact(DisplayName = "测试用例:加密请求中的敏感数据([POST] /refund/domestic/refunds/{refund_id}/apply-abnormal-refund)")]
public async Task TestEncryptRequestSensitiveProperty_CreateRefundDomesticAbnormalRefundApply()
{