Bläddra i källkod

[WeChatPay.V3] 支持解密敏感信息
增强 EncryptPrivacyProperty
新增 DecryptPrivacyProperty

Roc 3 år sedan
förälder
incheckning
d03106b8f1
1 ändrade filer med 90 tillägg och 26 borttagningar
  1. 90 26
      src/Essensoft.Paylink.WeChatPay/V3/WeChatPayClient.cs

+ 90 - 26
src/Essensoft.Paylink.WeChatPay/V3/WeChatPayClient.cs

@@ -1,5 +1,5 @@
 using System;
-using System.Collections;
+using System.Collections.Generic;
 using System.Net.Http;
 using System.Reflection;
 using System.Security.Cryptography;
@@ -171,6 +171,8 @@ namespace Essensoft.Paylink.WeChatPay.V3
                 await CheckResponseSignAsync(headers, body, options);
             }
 
+            DecryptPrivacyProperty(response, options.APIPrivateKey);
+
             return response;
         }
 
@@ -211,55 +213,117 @@ namespace Essensoft.Paylink.WeChatPay.V3
         /// </remarks>
         private static void EncryptPrivacyProperty(WeChatPayObject obj, RSA rsa)
         {
-            foreach (var propertyInfo in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
+            foreach (var propertyInfo in obj.GetType().GetProperties())
             {
-                if (propertyInfo.PropertyType == typeof(string)) // 为string类型
+                if (propertyInfo.PropertyType == typeof(string)) // 加密字符串
+                {
+                    if (!propertyInfo.IsDefined(typeof(WeChatPayPrivacyPropertyAttribute)))
+                    {
+                        continue;
+                    }
+
+                    var value = propertyInfo.GetValue(obj); // 获取值
+                    var strValue = value as string;
+                    if (string.IsNullOrEmpty(strValue))
+                    {
+                        propertyInfo.SetValue(obj, null);
+                        continue;
+                    }
+
+                    // 加密并将密文设置回对象
+                    var ciphertext = OaepSHA1WithRSA.Encrypt(rsa, strValue);
+                    propertyInfo.SetValue(obj, ciphertext);
+                }
+                else if (propertyInfo.PropertyType.IsClass) // 加密子对象
                 {
-                    if (propertyInfo.IsDefined(typeof(WeChatPayPrivacyPropertyAttribute), false)) // 是否标记为敏感信息
+                    if (propertyInfo.PropertyType.IsArray)
                     {
-                        var value = propertyInfo.GetValue(obj, null); // 获取值
-                        if (value is string strValue)
+                        if (propertyInfo.GetValue(obj) is WeChatPayObject[] array)
                         {
-                            if (string.IsNullOrEmpty(strValue))
+                            foreach (var item in array)
                             {
-                                continue; // 跳过空字符串
+                                EncryptPrivacyProperty(item, rsa);
                             }
-
-                            // 加密并将加密串设置回对象
-                            var strEncrypted = OaepSHA1WithRSA.Encrypt(rsa, strValue);
-                            propertyInfo.SetValue(obj, strEncrypted, null);
+                        }
+                    }
+                    if (propertyInfo.PropertyType.IsGenericType && typeof(IEnumerable<WeChatPayObject>).IsAssignableFrom(propertyInfo.PropertyType))
+                    {
+                        if (propertyInfo.GetValue(obj) is IEnumerable<WeChatPayObject> enumerable)
+                        {
+                            foreach (var item in enumerable)
+                            {
+                                EncryptPrivacyProperty(item, rsa);
+                            }
+                        }
+                    }
+                    else if(typeof(WeChatPayObject).IsAssignableFrom(propertyInfo.PropertyType))
+                    {
+                        if (propertyInfo.GetValue(obj) is WeChatPayObject wcpObj)
+                        {
+                            EncryptPrivacyProperty(wcpObj, rsa);
                         }
                     }
                 }
-                else if (propertyInfo.PropertyType.IsClass)
+            }
+        }
+
+        /// <summary>
+        /// 解密敏感信息字段
+        /// </summary>
+        /// <remarks>
+        /// <para><a href="https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_3.shtml">敏感信息加解密</a></para>
+        /// </remarks>
+        private static void DecryptPrivacyProperty(WeChatPayObject obj, string privateKey)
+        {
+            foreach (var propertyInfo in obj.GetType().GetProperties())
+            {
+                if (propertyInfo.PropertyType == typeof(string)) // 加密字符串
                 {
-                    var value = propertyInfo.GetValue(obj, null); // 获取子对象
-                    if (value is null)
+                    if (!propertyInfo.IsDefined(typeof(WeChatPayPrivacyPropertyAttribute)))
                     {
-                        continue; // 跳过空值
+                        continue;
                     }
 
-                    if (value is WeChatPayObject weChatPayObject)
+                    var value = propertyInfo.GetValue(obj); // 获取值
+                    var strValue = value as string;
+                    if (string.IsNullOrEmpty(strValue))
                     {
-                        EncryptPrivacyProperty(weChatPayObject, rsa); // 继续加密
+                        propertyInfo.SetValue(obj, null);
+                        continue;
                     }
-                    else if (value is IList list) // 获取列表对象
+
+                    // 解密并将明文设置回对象
+                    var ciphertext = OaepSHA1WithRSA.Decrypt(strValue, privateKey);
+                    propertyInfo.SetValue(obj, ciphertext);
+                }
+                else if (propertyInfo.PropertyType.IsClass) // 解密子对象
+                {
+                    if (propertyInfo.PropertyType.IsArray)
                     {
-                        foreach (var item in list)
+                        if (propertyInfo.GetValue(obj) is WeChatPayObject[] array)
                         {
-                            if (item is WeChatPayObject wcpObj)
+                            foreach (var item in array)
                             {
-                                EncryptPrivacyProperty(wcpObj, rsa); // 继续加密
+                                DecryptPrivacyProperty(item, privateKey);
                             }
-                            else
+                        }
+                    }
+                    if (propertyInfo.PropertyType.IsGenericType && typeof(IEnumerable<WeChatPayObject>).IsAssignableFrom(propertyInfo.PropertyType))
+                    {
+                        if (propertyInfo.GetValue(obj) is IEnumerable<WeChatPayObject> enumerable)
+                        {
+                            foreach (var item in enumerable)
                             {
-                                break;
+                                DecryptPrivacyProperty(item, privateKey);
                             }
                         }
                     }
-                    else
+                    else if(typeof(WeChatPayObject).IsAssignableFrom(propertyInfo.PropertyType))
                     {
-                        continue; // 跳过其他类型
+                        if (propertyInfo.GetValue(obj) is WeChatPayObject wcpObj)
+                        {
+                            DecryptPrivacyProperty(wcpObj, privateKey);
+                        }
                     }
                 }
             }