diff --git a/Samples/All/Senparc.Weixin.Sample.CommonService/Senparc.Weixin.Net8Sample.CommonService.csproj b/Samples/All/Senparc.Weixin.Sample.CommonService/Senparc.Weixin.Net8Sample.CommonService.csproj
index 92de20afdd..462a208942 100644
--- a/Samples/All/Senparc.Weixin.Sample.CommonService/Senparc.Weixin.Net8Sample.CommonService.csproj
+++ b/Samples/All/Senparc.Weixin.Sample.CommonService/Senparc.Weixin.Net8Sample.CommonService.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/Samples/All/net8-mvc/Senparc.Weixin.Sample.Net8/Senparc.Weixin.Sample.net8.csproj b/Samples/All/net8-mvc/Senparc.Weixin.Sample.Net8/Senparc.Weixin.Sample.net8.csproj
index 6da075e9cc..9ce0316929 100644
--- a/Samples/All/net8-mvc/Senparc.Weixin.Sample.Net8/Senparc.Weixin.Sample.net8.csproj
+++ b/Samples/All/net8-mvc/Senparc.Weixin.Sample.Net8/Senparc.Weixin.Sample.net8.csproj
@@ -20,9 +20,9 @@
-
-
-
+
+
+
diff --git a/src/Senparc.WebSocket/src/Senparc.WebSocket/Senparc.WebSocket/Senparc.WebSocket.net8.csproj b/src/Senparc.WebSocket/src/Senparc.WebSocket/Senparc.WebSocket/Senparc.WebSocket.net8.csproj
index 26c017ce81..fa88a22324 100644
--- a/src/Senparc.WebSocket/src/Senparc.WebSocket/Senparc.WebSocket/Senparc.WebSocket.net8.csproj
+++ b/src/Senparc.WebSocket/src/Senparc.WebSocket/Senparc.WebSocket/Senparc.WebSocket.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1;netcoreapp3.1;net8.0
- 1.1.5
+ 1.1.6
Senparc.WebSocket
Senparc.WebSocket
true
@@ -104,17 +104,12 @@
-
-
-
-
-
-
+
diff --git a/src/Senparc.Weixin.All/Senparc.Weixin.All.csproj b/src/Senparc.Weixin.All/Senparc.Weixin.All.csproj
index 1abd767162..7dcc6bb983 100644
--- a/src/Senparc.Weixin.All/Senparc.Weixin.All.csproj
+++ b/src/Senparc.Weixin.All/Senparc.Weixin.All.csproj
@@ -3,7 +3,7 @@
net8.0
enable
enable
- 2024.11.19
+ 2024.11.29
10.0
Senparc.Weixin.All
Senparc.Weixin.All
diff --git a/src/Senparc.Weixin.AspNet/Senparc.Weixin.AspNet.net8.csproj b/src/Senparc.Weixin.AspNet/Senparc.Weixin.AspNet.net8.csproj
index 9ad5496fd1..97f062a554 100644
--- a/src/Senparc.Weixin.AspNet/Senparc.Weixin.AspNet.net8.csproj
+++ b/src/Senparc.Weixin.AspNet/Senparc.Weixin.AspNet.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1
- 1.4.6
+ 1.4.7
Senparc.Weixin.AspNet
Senparc.Weixin.AspNet
@@ -74,7 +74,7 @@
-
+
diff --git a/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.CsRedis/Senparc.Weixin.Cache.CsRedis.net8.csproj b/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.CsRedis/Senparc.Weixin.Cache.CsRedis.net8.csproj
index 7153cf9006..c959fd42d5 100644
--- a/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.CsRedis/Senparc.Weixin.Cache.CsRedis.net8.csproj
+++ b/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.CsRedis/Senparc.Weixin.Cache.CsRedis.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1
- 1.1.4
+ 1.1.5
Senparc.Weixin.Cache.CsRedis
Senparc.Weixin.Cache.CsRedis
true
@@ -61,7 +61,7 @@
-
+
diff --git a/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Dapr/Senparc.Weixin.Cache.Dapr.net8.csproj b/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Dapr/Senparc.Weixin.Cache.Dapr.net8.csproj
index e8ddd769bf..3c5517bec1 100644
--- a/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Dapr/Senparc.Weixin.Cache.Dapr.net8.csproj
+++ b/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Dapr/Senparc.Weixin.Cache.Dapr.net8.csproj
@@ -1,7 +1,7 @@
net8.0
- 0.2.4-beta1
+ 0.2.5-beta1
Senparc.Weixin.Cache.Dapr
Senparc.Weixin.Cache.Dapr
true
@@ -56,7 +56,7 @@
-
+
diff --git a/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Memcached/Senparc.Weixin.Cache.Memcached.net8.csproj b/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Memcached/Senparc.Weixin.Cache.Memcached.net8.csproj
index 209ace594d..c2af0a2ded 100644
--- a/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Memcached/Senparc.Weixin.Cache.Memcached.net8.csproj
+++ b/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Memcached/Senparc.Weixin.Cache.Memcached.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1
- 2.18.5
+ 2.18.6
Senparc.Weixin.Cache.Memcached
Senparc.Weixin.Cache.Memcached
@@ -143,7 +143,7 @@
-
+
diff --git a/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Redis/Senparc.Weixin.Cache.Redis.net8.csproj b/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Redis/Senparc.Weixin.Cache.Redis.net8.csproj
index 8d86cb1305..810efaa7d9 100644
--- a/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Redis/Senparc.Weixin.Cache.Redis.net8.csproj
+++ b/src/Senparc.Weixin.Cache/Senparc.Weixin.Cache.Redis/Senparc.Weixin.Cache.Redis.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1
- 2.20.5
+ 2.20.6
Senparc.Weixin.Cache.Redis
Senparc.Weixin.Cache.Redis
true
@@ -133,7 +133,7 @@
-
+
diff --git a/src/Senparc.Weixin.MP.Middleware/Senparc.Weixin.MP.Middleware.net8.csproj b/src/Senparc.Weixin.MP.Middleware/Senparc.Weixin.MP.Middleware.net8.csproj
index 193ba75df2..c7cbf7f307 100644
--- a/src/Senparc.Weixin.MP.Middleware/Senparc.Weixin.MP.Middleware.net8.csproj
+++ b/src/Senparc.Weixin.MP.Middleware/Senparc.Weixin.MP.Middleware.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1;netcoreapp3.1;net8.0
- 1.4.6
+ 1.4.7
Senparc.Weixin.MP.Middleware
Senparc.Weixin.MP.Middleware
true
@@ -72,7 +72,7 @@
-
+
diff --git a/src/Senparc.Weixin.MP.MvcExtension/Senparc.Weixin.MP.MvcExtension/Senparc.Weixin.MP.MvcExtension.net8.csproj b/src/Senparc.Weixin.MP.MvcExtension/Senparc.Weixin.MP.MvcExtension/Senparc.Weixin.MP.MvcExtension.net8.csproj
index a33c4a3784..e61b42ad11 100644
--- a/src/Senparc.Weixin.MP.MvcExtension/Senparc.Weixin.MP.MvcExtension/Senparc.Weixin.MP.MvcExtension.net8.csproj
+++ b/src/Senparc.Weixin.MP.MvcExtension/Senparc.Weixin.MP.MvcExtension/Senparc.Weixin.MP.MvcExtension.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1;netcoreapp3.1;net8.0
- 7.16.6
+ 7.16.7
Senparc.Weixin.MP.MvcExtension
Senparc.Weixin.MP.MvcExtension
true
@@ -148,7 +148,7 @@
-
+
diff --git a/src/Senparc.Weixin.MP/Senparc.Weixin.MP/AdvancedAPIs/Media/MediaApi.cs b/src/Senparc.Weixin.MP/Senparc.Weixin.MP/AdvancedAPIs/Media/MediaApi.cs
index 068fc07b2a..100141d473 100644
--- a/src/Senparc.Weixin.MP/Senparc.Weixin.MP/AdvancedAPIs/Media/MediaApi.cs
+++ b/src/Senparc.Weixin.MP/Senparc.Weixin.MP/AdvancedAPIs/Media/MediaApi.cs
@@ -590,7 +590,7 @@ public static async Task UploadTemporaryMediaAsync(s
var url = string.Format(Config.ApiMpHost + "/cgi-bin/media/upload?access_token={0}&type={1}", accessToken.AsUrlData(), type.ToString().AsUrlData());
var fileDictionary = new Dictionary();
fileDictionary["media"] = file;
- return await CO2NET.HttpUtility.Post.PostFileGetJsonAsync(CommonDI.CommonSP, url, null, fileDictionary, null, null, null, false, timeOut: timeOut).ConfigureAwait(false);
+ return await CO2NET.HttpUtility.Post.PostFileGetJsonAsync(CommonDI.CommonSP, url, null, fileDictionary, timeOut: timeOut).ConfigureAwait(false);
}, accessTokenOrAppId).ConfigureAwait(false);
}
diff --git a/src/Senparc.Weixin.MP/Senparc.Weixin.MP/AdvancedAPIs/OAuth/OAuthJson/OAuthAccessTokenResult.cs b/src/Senparc.Weixin.MP/Senparc.Weixin.MP/AdvancedAPIs/OAuth/OAuthJson/OAuthAccessTokenResult.cs
index 3454c88afe..c9d440f111 100644
--- a/src/Senparc.Weixin.MP/Senparc.Weixin.MP/AdvancedAPIs/OAuth/OAuthJson/OAuthAccessTokenResult.cs
+++ b/src/Senparc.Weixin.MP/Senparc.Weixin.MP/AdvancedAPIs/OAuth/OAuthJson/OAuthAccessTokenResult.cs
@@ -41,6 +41,8 @@ and limitations under the License.
修改标识:Senparc - 20220910
修改说明:v16.18.6 OAuth 的 AccessToken 获取接口添加 is_snapshotuser 返回值
+
+
----------------------------------------------------------------*/
using System;
diff --git a/src/Senparc.Weixin.MP/Senparc.Weixin.MP/Senparc.Weixin.MP.net8.csproj b/src/Senparc.Weixin.MP/Senparc.Weixin.MP/Senparc.Weixin.MP.net8.csproj
index 114c42980e..2151f6020a 100644
--- a/src/Senparc.Weixin.MP/Senparc.Weixin.MP/Senparc.Weixin.MP.net8.csproj
+++ b/src/Senparc.Weixin.MP/Senparc.Weixin.MP/Senparc.Weixin.MP.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1
- 16.23.5
+ 16.23.6
Senparc.Weixin.MP
Senparc.Weixin.MP
true
@@ -576,9 +576,9 @@
-
-
-
+
+
+
diff --git a/src/Senparc.Weixin.Open/Senparc.Weixin.Open/OAuthAPIs/OAuthJson/OAuthAccessTokenResult.cs b/src/Senparc.Weixin.Open/Senparc.Weixin.Open/OAuthAPIs/OAuthJson/OAuthAccessTokenResult.cs
index 48ef5c0fa0..942d54a729 100644
--- a/src/Senparc.Weixin.Open/Senparc.Weixin.Open/OAuthAPIs/OAuthJson/OAuthAccessTokenResult.cs
+++ b/src/Senparc.Weixin.Open/Senparc.Weixin.Open/OAuthAPIs/OAuthJson/OAuthAccessTokenResult.cs
@@ -9,6 +9,9 @@
修改标识:Senparc - 20161216
修改描述:v2.3.5 添加序列化特性
+
+ 修改标识:Senparc - 20241129
+ 修改描述:v4.21.8 返回值添加参数 is_snapshotuser 和 unionid
----------------------------------------------------------------*/
@@ -44,5 +47,13 @@ public class OAuthAccessTokenResult : WxJsonResult
/// 用户授权的作用域,使用逗号(,)分隔
///
public string scope { get; set; }
+ ///
+ /// 用户统一标识(针对一个微信开放平台账号下的应用,同一用户的 unionid 是唯一的),只有当scope为"snsapi_userinfo"时返回
+ ///
+ public string unionid { get; set; }
+ ///
+ /// 是否为快照页模式虚拟账号,只有当用户是快照页模式虚拟账号是返回,值为1
+ ///
+ public int? is_snapshotuser { get; set; }
}
}
diff --git a/src/Senparc.Weixin.Open/Senparc.Weixin.Open/Senparc.Weixin.Open.net8.csproj b/src/Senparc.Weixin.Open/Senparc.Weixin.Open/Senparc.Weixin.Open.net8.csproj
index 04549d48c1..7b119dd4c4 100644
--- a/src/Senparc.Weixin.Open/Senparc.Weixin.Open/Senparc.Weixin.Open.net8.csproj
+++ b/src/Senparc.Weixin.Open/Senparc.Weixin.Open/Senparc.Weixin.Open.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1
- 4.21.7
+ 4.21.9
Senparc.Weixin.Open
Senparc.Weixin.Open
true
@@ -227,6 +227,7 @@
[2024-08-11] v4.20.0.0 1、添加查询小程序是否已完成交易结算管理确认 2、添加第三方小程序订单页设置结果及审核结果事件通知 #3055 感谢 @mc7246
[2024-09-10] v4.20.2 icp verifytask 接口 data 不能为 null 的问题处理 #3067 感谢 @mojinxun
[2024-11-03] v4.20.6 fix wxa ap is get qr code async Issue #3089, PR #3090 感谢 @JaneConan
+ [2024-11-29] v4.21.8 返回值添加参数 is_snapshotuser 和 unionid #3100 感谢 @ccccccmd
https://github.com/JeffreySu/WeiXinMPSDK
@@ -270,7 +271,7 @@
-
+
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPay/Senparc.Weixin.TenPay.net8.csproj b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPay/Senparc.Weixin.TenPay.net8.csproj
index 633ea6672b..a4cd9e4231 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPay/Senparc.Weixin.TenPay.net8.csproj
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPay/Senparc.Weixin.TenPay.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1
- 1.17.5
+ 1.17.6
Senparc.Weixin.TenPay
Senparc.Weixin.TenPay
true
@@ -97,7 +97,7 @@
-
+
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/Apis/Profitsharing/ProfitsharingApisTest.cs b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/Apis/Profitsharing/ProfitsharingApisTest.cs
index db21f9914d..625da8f556 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/Apis/Profitsharing/ProfitsharingApisTest.cs
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/Apis/Profitsharing/ProfitsharingApisTest.cs
@@ -12,6 +12,7 @@
namespace Senparc.Weixin.TenPayV3.Test.net6.Apis
{
+ [TestClass()]
public class ProfitsharingApisTest : BaseTenPayTest
{
#region 分账接口
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/Senparc.Weixin.TenPayV3.Test.net8.csproj b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/Senparc.Weixin.TenPayV3.Test.net8.csproj
index 0b00522295..e9b023f2fc 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/Senparc.Weixin.TenPayV3.Test.net8.csproj
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/Senparc.Weixin.TenPayV3.Test.net8.csproj
@@ -18,11 +18,6 @@
true
PreserveNewest
-
- PreserveNewest
- true
- PreserveNewest
-
PreserveNewest
true
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/appsettings.json b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/appsettings.json
index d5cecc784d..2dc4d0f689 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/appsettings.json
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3.Test/appsettings.json
@@ -72,6 +72,8 @@
"TenPayV3_PrivateKey": "#{TenPayV3_PrivateKey}#", //(新)证书私钥
"TenPayV3_SerialNumber": "#{TenPayV3_SerialNumber}#", //(新)证书序列号
"TenPayV3_ApiV3Key": "#{TenPayV3_APIv3Key}#", //(新)APIv3 密钥
+ "TenPayV3_TenPayPubKey": "#{TenPayV3_TenPayPubKey}#", // (新)微信支付公钥证书-验证微信支付身份,支持本地项目路径/字符串,空则代表使用原来的平台证书,如:D:\\cert\\cert.pem
+ "TenPayV3_TenPayPubKeyID": "#{TenPayV3_TenPayPubKeyID}#", // (新)微信支付公钥ID-验证微信支付身份,空则代表使用原来的平台证书,如PUB_KEY_ID_0000000000000000000000
//如果不设置TenPayV3_WxOpenTenpayNotify,默认在 TenPayV3_TenpayNotify 的值最后加上 "WxOpen"
"TenPayV3_WxOpenTenpayNotify": "#{TenPayV3_WxOpenTenpayNotify}#", //http://YourDomainName/TenpayV3/PayNotifyUrlWxOpen
//开放平台
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Apis/BasePay/BasePayApis.cs b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Apis/BasePay/BasePayApis.cs
index 627e5ef2f1..b049924766 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Apis/BasePay/BasePayApis.cs
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Apis/BasePay/BasePayApis.cs
@@ -118,7 +118,7 @@ internal static string GetPayApiUrl(string urlFormat, string sp_mchid = "")
///
public async Task CertificatesAsync(string algorithmType = "RSA", int timeOut = Config.TIME_OUT)
{
- var url = BasePayApis.GetPayApiUrl(Senparc.Weixin.Config.TenPayV3Host + "/{0}v3/certificates?algorithm_type=" + algorithmType);
+ var url = GetPayApiUrl(Senparc.Weixin.Config.TenPayV3Host + "/{0}v3/certificates?algorithm_type=" + algorithmType);
TenPayApiRequest tenPayApiRequest = new(_tenpayV3Setting);
//var responseMessge = await tenPayApiRequest.GetHttpResponseMessageAsync(url, null, timeOut);
//return await responseMessge.Content.ReadAsStringAsync();
@@ -132,7 +132,15 @@ public async Task CertificatesAsync(string algorithmType
///
public async Task GetPublicKeysAsync(/*int timeOut = Config.TIME_OUT*/)
{
- string algorithmType = _tenpayV3Setting.EncryptionType == CertType.SM.ToString() ? "SM2" : "RSA";
+ PublicKeyCollection keys = new();
+
+ if (_tenpayV3Setting.TenPayV3_TenPayPubKeyEnable)
+ {
+ keys[_tenpayV3Setting.TenPayV3_TenPayPubKeyID] = SecurityHelper.GetUnwrapCertKey(_tenpayV3Setting.TenPayV3_TenPayPubKey);
+ return keys;
+ }
+
+ var algorithmType = _tenpayV3Setting.EncryptionType == CertType.SM.ToString() ? "SM2" : "RSA";
var certificates = await CertificatesAsync(algorithmType);
if (!certificates.ResultCode.Success)
{
@@ -144,12 +152,11 @@ public async Task GetPublicKeysAsync(/*int timeOut = Config
throw new TenpayApiRequestException("Certificates 获取结果为空");
}
- PublicKeyCollection keys = new();
//var tenpayV3Setting = Senparc.Weixin.Config.SenparcWeixinSetting.TenpayV3Setting;//TODO:改成从构造函数配置
foreach (var cert in certificates.data)
{
- if(cert.encrypt_certificate.algorithm == "AEAD_AES_256_GCM")
+ if (cert.encrypt_certificate.algorithm == "AEAD_AES_256_GCM")
{
var publicKey = SecurityHelper.AesGcmDecryptCiphertext(_tenpayV3Setting.TenPayV3_APIv3Key, cert.encrypt_certificate.nonce,
cert.encrypt_certificate.associated_data, cert.encrypt_certificate.ciphertext);
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Apis/Profitsharing/ProfitsharingApis.cs b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Apis/Profitsharing/ProfitsharingApis.cs
index 63b3b7ef4b..e24d7f92db 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Apis/Profitsharing/ProfitsharingApis.cs
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Apis/Profitsharing/ProfitsharingApis.cs
@@ -111,18 +111,24 @@ public async Task CreateProfitsharingAsync(Create
// name加密
var basePayApis = new BasePayApis();
-
- string algorithmType = _tenpayV3Setting.EncryptionType == CertType.SM.ToString() ? "SM2" : "RSA";
- var certificateResponse = await basePayApis.CertificatesAsync(algorithmType);
+ var publicKeys = await basePayApis.GetPublicKeysAsync();
+ var publicKeyKv = publicKeys.FirstOrDefault();
foreach (var each in data.receivers)
{
- SecurityHelper.FieldEncrypt(each, certificateResponse, _tenpayV3Setting.TenPayV3_APIv3Key, _tenpayV3Setting.EncryptionType);
+ SecurityHelper.FieldEncrypt(each, publicKeyKv.Value, _tenpayV3Setting.EncryptionType, _tenpayV3Setting.TenPayV3_TenPayPubKeyEnable);
}
+ //string algorithmType = _tenpayV3Setting.EncryptionType == CertType.SM.ToString() ? "SM2" : "RSA";
+ //var certificateResponse = await basePayApis.CertificatesAsync(algorithmType);
+ //foreach (var each in data.receivers)
+ //{
+ // SecurityHelper.FieldEncrypt(each, certificateResponse, _tenpayV3Setting.TenPayV3_APIv3Key, _tenpayV3Setting.EncryptionType);
+ //}
+
var url = ReurnPayApiUrl(Senparc.Weixin.Config.TenPayV3Host + "/{0}v3/{1}profitsharing/orders", data.brand_mchid);
TenPayApiRequest tenPayApiRequest = new(_tenpayV3Setting, httpClient =>
{
- httpClient.DefaultRequestHeaders.Add("Wechatpay-Serial", certificateResponse.data?.FirstOrDefault()?.serial_no);
+ httpClient.DefaultRequestHeaders.Add("Wechatpay-Serial", publicKeyKv.Key);
});
return await tenPayApiRequest.RequestAsync(url, data, timeOut);
}
@@ -316,14 +322,18 @@ public async Task AddProfitsharingReceiverAs
// name加密
var basePayApis = new BasePayApis();
- string algorithmType = _tenpayV3Setting.EncryptionType == CertType.SM.ToString() ? "SM2" : "RSA";
- var certificateResponse = await basePayApis.CertificatesAsync(algorithmType);
- SecurityHelper.FieldEncrypt(data, certificateResponse, _tenpayV3Setting.TenPayV3_APIv3Key, _tenpayV3Setting.EncryptionType);
+ var publicKeys = await basePayApis.GetPublicKeysAsync();
+ var publicKeyKv = publicKeys.FirstOrDefault();
+ SecurityHelper.FieldEncrypt(data, publicKeyKv.Value, _tenpayV3Setting.EncryptionType, _tenpayV3Setting.TenPayV3_TenPayPubKeyEnable);
+
+ //string algorithmType = _tenpayV3Setting.EncryptionType == CertType.SM.ToString() ? "SM2" : "RSA";
+ //var certificateResponse = await basePayApis.CertificatesAsync(algorithmType);
+ //SecurityHelper.FieldEncrypt(data, certificateResponse, _tenpayV3Setting.TenPayV3_APIv3Key, _tenpayV3Setting.EncryptionType);
var url = ReurnPayApiUrl(Senparc.Weixin.Config.TenPayV3Host + "/{0}v3/{1}profitsharing/receivers/add", data.brand_mchid);
TenPayApiRequest tenPayApiRequest = new(_tenpayV3Setting, httpClient =>
{
- httpClient.DefaultRequestHeaders.Add("Wechatpay-Serial", certificateResponse.data?.FirstOrDefault()?.serial_no);
+ httpClient.DefaultRequestHeaders.Add("Wechatpay-Serial", publicKeyKv.Key);
});
return await tenPayApiRequest.RequestAsync(url, data, timeOut);
}
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Enums.cs b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Enums.cs
index 67186935cc..6fce1d1bd0 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Enums.cs
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Enums.cs
@@ -62,6 +62,9 @@ public enum ApiRequestMethod
public enum CertType
{
RSA,
- SM
+ SM,
+
+ PUBKEY_RSA,
+ PUBKEY_SM
}
}
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Helpers/SecurityHelper.cs b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Helpers/SecurityHelper.cs
index fea264bc0f..d371f09efc 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Helpers/SecurityHelper.cs
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Helpers/SecurityHelper.cs
@@ -35,6 +35,7 @@ and limitations under the License.
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
using Senparc.CO2NET.Helpers;
using Senparc.Weixin.TenPayV3.Apis;
using Senparc.Weixin.TenPayV3.Apis.BasePay;
@@ -47,6 +48,7 @@ and limitations under the License.
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
+using System.Xml;
namespace Senparc.Weixin.TenPayV3.Helpers
{
@@ -76,47 +78,31 @@ public static string GetUnwrapCertKey(string originalPublicKey)
}
///
- /// 敏感信息加密需要从https://api.mch.weixin.qq.com/risk/getcertficates此接口下载加密证书进行下一步加密,
- /// 该接口下载到的是密文,使用此AESGCM.Decrypt()方法解密得到证书明文
+ /// 加密敏感信息,传入明文和从微信支付获取到的敏感信息加密公钥,事先使用OpenSSL转换cert.pem文件输出为der文件
///
- ///
- ///
+ ///
+ ///
///
+ /// 是否是微信支付公钥
///
- public static string GetPublicKey(Encrypt_Certificate encryptCertificate, string apiV3Key, string encryptionType)
+ public static string Encrypt(string text, string publicKey, string encryptionType, bool isWeixinPubKey = false)
{
- if (encryptionType == CertType.SM.ToString())
- {
- return GmHelper.Sm4DecryptGCM(apiV3Key, encryptCertificate.nonce, "certificate", encryptCertificate.ciphertext);
- }
- else
+ #region 基于微信支付公钥
+ if (isWeixinPubKey)
{
- var buff = Convert.FromBase64String(encryptCertificate.ciphertext);
- var secret = Encoding.UTF8.GetBytes(apiV3Key);
- var nonce = Encoding.UTF8.GetBytes(encryptCertificate.nonce);
- var associatedData = Encoding.UTF8.GetBytes("certificate");
-
- // 算法 AEAD_AES_256_GCM,C# 环境使用 BouncyCastle.Crypto.dll 类库实现
- var cipher = new GcmBlockCipher(new AesEngine());
- var aead = new AeadParameters(new KeyParameter(secret), 128, nonce, associatedData);
- cipher.Init(false, aead);
+ var publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
+ var publicKeyXml = string.Format("{0}{1}",
+ Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
+ Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
- var data = new byte[cipher.GetOutputSize(buff.Length)];
- var num = cipher.ProcessBytes(buff, 0, buff.Length, data, 0);
- cipher.DoFinal(data, num);
- return Encoding.UTF8.GetString(data);
+ var rsa = new RSACryptoServiceProvider();
+ RSAFromXmlString(rsa, publicKeyXml);
+ var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
+ return Convert.ToBase64String(buff);
}
- }
+ #endregion
+
- ///
- /// 加密敏感信息,传入明文和从微信支付获取到的敏感信息加密公钥,事先使用OpenSSL转换cert.pem文件输出为der文件
- ///
- ///
- ///
- ///
- ///
- public static string Encrypt(string text, string publicKey, string encryptionType)
- {
if (encryptionType == CertType.SM.ToString())
{
ECPublicKeyParameters eCPublicKeyParameters = SMPemHelper.LoadPublicKeyToParameters(Encoding.UTF8.GetBytes(publicKey));
@@ -137,7 +123,8 @@ public static string Encrypt(string text, string publicKey, string encryptionTyp
///
///
///
- public static void FieldEncrypt(object request, string publicKey, string encryptionType)
+ /// 是否是微信支付公钥
+ public static void FieldEncrypt(object request, string publicKey, string encryptionType, bool isWeixinPubKey = false)
{
var pis = request.GetType().GetProperties();
foreach (var pi in pis)
@@ -148,14 +135,14 @@ public static void FieldEncrypt(object request, string publicKey, string encrypt
if (!(pi.PropertyType.IsValueType || pi.PropertyType.Name.StartsWith("String") || typeof(IEnumerable).IsAssignableFrom(pi.PropertyType)))
{
- FieldEncrypt(value, publicKey, encryptionType);
+ FieldEncrypt(value, publicKey, encryptionType, isWeixinPubKey);
continue;
}
if ((pi.GetCustomAttributes(typeof(FieldEncryptAttribute), true)?.Count() ?? 0) <= 0)
continue;
- var encryptValue = Encrypt(value.ToString(), publicKey, encryptionType);
+ var encryptValue = Encrypt(value.ToString(), publicKey, encryptionType, isWeixinPubKey);
pi.SetValue(request, encryptValue);
}
}
@@ -168,6 +155,24 @@ public static void FieldEncrypt(object request, string publicKey, string encrypt
///
///
///
+ [Obsolete("放弃使用")]
+ public static async Task FieldEncryptAsync(object request, string apiV3Key, string encryptionType)
+ {
+ // name 敏感信息加密
+ var basePayApis = new BasePayApis();
+ var certificate = await basePayApis.CertificatesAsync();
+ FieldEncrypt(request, certificate, apiV3Key, encryptionType);
+ }
+
+ ///
+ /// 字段加密
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [Obsolete("放弃使用")]
public static void FieldEncrypt(object request, CertificatesResultJson certificate, string apiV3Key, string encryptionType)
{
if (!(certificate?.ResultCode?.Success ?? false))
@@ -179,19 +184,99 @@ public static void FieldEncrypt(object request, CertificatesResultJson certifica
}
///
- /// 字段加密
+ /// 敏感信息加密需要从https://api.mch.weixin.qq.com/risk/getcertficates此接口下载加密证书进行下一步加密,
+ /// 该接口下载到的是密文,使用此AESGCM.Decrypt()方法解密得到证书明文
///
- ///
+ ///
///
///
///
- ///
- public static async Task FieldEncryptAsync(object request, string apiV3Key, string encryptionType)
+ public static string GetPublicKey(Encrypt_Certificate encryptCertificate, string apiV3Key, string encryptionType)
{
- // name 敏感信息加密
- var basePayApis = new BasePayApis();
- var certificate = await basePayApis.CertificatesAsync();
- FieldEncrypt(request, certificate, apiV3Key, encryptionType);
+ if (encryptionType == CertType.SM.ToString())
+ {
+ return GmHelper.Sm4DecryptGCM(apiV3Key, encryptCertificate.nonce, "certificate", encryptCertificate.ciphertext);
+ }
+ else
+ {
+ var buff = Convert.FromBase64String(encryptCertificate.ciphertext);
+ var secret = Encoding.UTF8.GetBytes(apiV3Key);
+ var nonce = Encoding.UTF8.GetBytes(encryptCertificate.nonce);
+ var associatedData = Encoding.UTF8.GetBytes("certificate");
+
+ // 算法 AEAD_AES_256_GCM,C# 环境使用 BouncyCastle.Crypto.dll 类库实现
+ var cipher = new GcmBlockCipher(new AesEngine());
+ var aead = new AeadParameters(new KeyParameter(secret), 128, nonce, associatedData);
+ cipher.Init(false, aead);
+
+ var data = new byte[cipher.GetOutputSize(buff.Length)];
+ var num = cipher.ProcessBytes(buff, 0, buff.Length, data, 0);
+ cipher.DoFinal(data, num);
+ return Encoding.UTF8.GetString(data);
+ }
+ }
+
+ public static void RSAFromXmlString(RSA rsa, string xmlString)
+ {
+ var parameters = new RSAParameters();
+ var xmlDoc = new XmlDocument();
+ xmlDoc.LoadXml(xmlString);
+
+ if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
+ {
+ foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
+ {
+ switch (node.Name)
+ {
+ case "Modulus":
+ parameters.Modulus = (string.IsNullOrEmpty(node.InnerText)
+ ? null
+ : Convert.FromBase64String(node.InnerText));
+ break;
+ case "Exponent":
+ parameters.Exponent = (string.IsNullOrEmpty(node.InnerText)
+ ? null
+ : Convert.FromBase64String(node.InnerText));
+ break;
+ case "P":
+ parameters.P = (string.IsNullOrEmpty(node.InnerText)
+ ? null
+ : Convert.FromBase64String(node.InnerText));
+ break;
+ case "Q":
+ parameters.Q = (string.IsNullOrEmpty(node.InnerText)
+ ? null
+ : Convert.FromBase64String(node.InnerText));
+ break;
+ case "DP":
+ parameters.DP = (string.IsNullOrEmpty(node.InnerText)
+ ? null
+ : Convert.FromBase64String(node.InnerText));
+ break;
+ case "DQ":
+ parameters.DQ = (string.IsNullOrEmpty(node.InnerText)
+ ? null
+ : Convert.FromBase64String(node.InnerText));
+ break;
+ case "InverseQ":
+ parameters.InverseQ = (string.IsNullOrEmpty(node.InnerText)
+ ? null
+ : Convert.FromBase64String(node.InnerText));
+ break;
+ case "D":
+ parameters.D = (string.IsNullOrEmpty(node.InnerText)
+ ? null
+ : Convert.FromBase64String(node.InnerText));
+ break;
+ }
+ }
+ }
+ else
+ {
+ throw new Exception("Invalid XML RSA key.");
+ }
+
+ rsa.ImportParameters(parameters);
}
}
}
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Helpers/TenPaySignHelper.cs b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Helpers/TenPaySignHelper.cs
index 76f3745305..e39dfa07de 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Helpers/TenPaySignHelper.cs
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Helpers/TenPaySignHelper.cs
@@ -37,6 +37,7 @@ and limitations under the License.
using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
using Senparc.Weixin.Entities;
using Senparc.Weixin.Helpers;
using System;
@@ -127,18 +128,44 @@ public static string CreatePaySign(string timeStamp, string nonceStr, string pac
/// HTTP头中的应答随机串
/// HTTP头中的应答签名(Base64)
/// 应答报文主体
- /// 平台公钥(必须是Unwrap的公钥)
+ /// 平台公钥/微信支付公钥(必须是Unwrap的公钥)
+ /// 是否是微信支付公钥
///
- public static bool VerifyTenpaySign(string wechatpayTimestamp, string wechatpayNonce, string wechatpaySignatureBase64, string content, string pubKey)
+ public static bool VerifyTenpaySign(string wechatpayTimestamp, string wechatpayNonce, string wechatpaySignatureBase64, string content, string pubKey, bool isTenPayPubKey = false)
{
//验签名串
- string contentForSign = $"{wechatpayTimestamp}\n{wechatpayNonce}\n{content}\n";
+ var contentForSign = $"{wechatpayTimestamp}\n{wechatpayNonce}\n{content}\n";
- if(Senparc.Weixin.Config.SenparcWeixinSetting.EncryptionType == CertType.SM.ToString())
+ if (isTenPayPubKey)
+ {
+ var publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(pubKey));
+ var publicKeyXml = string.Format("{0}{1}",
+ Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
+ Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
+
+ var rsa = new RSACryptoServiceProvider();
+ SecurityHelper.RSAFromXmlString(rsa, publicKeyXml);
+
+ //RSAPKCS1SignatureDeformatter 对象
+ RSAPKCS1SignatureDeformatter df = new RSAPKCS1SignatureDeformatter(rsa);
+ //指定 SHA256
+ df.SetHashAlgorithm("SHA256");
+ //SHA256Managed 方法已弃用,使用 SHA256.Create() 生成 SHA256 对象
+ var sha256 = SHA256.Create();
+ //应答签名
+ byte[] signature = Convert.FromBase64String(wechatpaySignatureBase64);
+ //对比签名
+ byte[] compareByte = sha256.ComputeHash(Encoding.UTF8.GetBytes(contentForSign));
+ //验证签名
+ var result = df.VerifySignature(compareByte, signature);
+ return result;
+ }
+
+
+ if (Senparc.Weixin.Config.SenparcWeixinSetting.EncryptionType == CertType.SM.ToString())
{
byte[] pubKeyBytes = Convert.FromBase64String(pubKey);
ECPublicKeyParameters eCPublicKeyParameters = SMPemHelper.LoadPublicKeyToParameters(pubKeyBytes);
-
return GmHelper.VerifySm3WithSm2(eCPublicKeyParameters, contentForSign, wechatpaySignatureBase64);
}
else
@@ -184,7 +211,7 @@ public static async Task VerifyTenpaySign(string wechatpayTimestamp, strin
var tenpayV3InfoKey = TenPayHelper.GetRegisterKey(senparcWeixinSettingForTenpayV3.TenPayV3_MchId, senparcWeixinSettingForTenpayV3.TenPayV3_SubMchId);
var pubKey = await TenPayV3InfoCollection.Data[tenpayV3InfoKey].GetPublicKeyAsync(serialNumber, senparcWeixinSettingForTenpayV3);
- return VerifyTenpaySign(wechatpayTimestamp, wechatpayNonce, wechatpaySignature, content, pubKey);
+ return VerifyTenpaySign(wechatpayTimestamp, wechatpayNonce, wechatpaySignature, content, pubKey, senparcWeixinSettingForTenpayV3.TenPayV3_TenPayPubKeyEnable);
}
///
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/HttpHandlers/TenPayApiRequest.cs b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/HttpHandlers/TenPayApiRequest.cs
index d54d243ab2..8c2303aea2 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/HttpHandlers/TenPayApiRequest.cs
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/HttpHandlers/TenPayApiRequest.cs
@@ -231,7 +231,7 @@ public async Task RequestAsync(string url, object data, int timeOut = Conf
try
{
var pubKey = await TenPayV3InfoCollection.GetAPIv3PublicKeyAsync(this._tenpayV3Setting, wechatpaySerial);
- if(this._tenpayV3Setting.EncryptionType == CertType.SM.ToString())
+ if (this._tenpayV3Setting.EncryptionType == CertType.SM.ToString())
{
byte[] pubKeyBytes = Convert.FromBase64String(pubKey);
ECPublicKeyParameters eCPublicKeyParameters = SMPemHelper.LoadPublicKeyToParameters(pubKeyBytes);
@@ -243,7 +243,7 @@ public async Task RequestAsync(string url, object data, int timeOut = Conf
}
else
{
- result.VerifySignSuccess = TenPaySignHelper.VerifyTenpaySign(wechatpayTimestamp, wechatpayNonce, wechatpaySignatureBase64, content, pubKey);
+ result.VerifySignSuccess = TenPaySignHelper.VerifyTenpaySign(wechatpayTimestamp, wechatpayNonce, wechatpaySignatureBase64, content, pubKey, _tenpayV3Setting.TenPayV3_TenPayPubKeyEnable);
}
}
catch (Exception ex)
diff --git a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Senparc.Weixin.TenPayV3.net8.csproj b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Senparc.Weixin.TenPayV3.net8.csproj
index 029ecd8adc..9a133150ba 100644
--- a/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Senparc.Weixin.TenPayV3.net8.csproj
+++ b/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/Senparc.Weixin.TenPayV3.net8.csproj
@@ -1,7 +1,7 @@
netstandard2.1
- 1.7.7
+ 1.7.8
Senparc.Weixin.TenPayV3
Senparc.Weixin.TenPayV3
10.0
@@ -58,7 +58,8 @@
v1.4.2 完善 SM 相关方法
v1.6.3 更新支付接口调用过程中的 SM 和 RSA 判断方式
v1.6.5 修改 SM 证书判断逻辑,向下兼容未升级 appsettings.json 的系统 #3084
-
+ v1.7.8 兼容微信支付公钥以及平台证书 / PR #3103 感谢 @mojinxun
+
https://github.com/JeffreySu/WeiXinMPSDK
@@ -90,7 +91,7 @@
-
+
diff --git a/src/Senparc.Weixin.Work.Middleware/Senparc.Weixin.Work.Middleware.net8.csproj b/src/Senparc.Weixin.Work.Middleware/Senparc.Weixin.Work.Middleware.net8.csproj
index 3cf9e470f1..0f0bc509a8 100644
--- a/src/Senparc.Weixin.Work.Middleware/Senparc.Weixin.Work.Middleware.net8.csproj
+++ b/src/Senparc.Weixin.Work.Middleware/Senparc.Weixin.Work.Middleware.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1;netcoreapp3.1;net8.0
- 1.4.6
+ 1.4.7
Senparc.Weixin.Work.Middleware
Senparc.Weixin.Work.Middleware
true
@@ -69,7 +69,7 @@
-
+
diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Media/MediaApi.cs b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Media/MediaApi.cs
index 27b025b989..0b070057bc 100644
--- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Media/MediaApi.cs
+++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/Media/MediaApi.cs
@@ -71,10 +71,8 @@ public static UploadTemporaryResultJson Upload(string accessTokenOrAppKey, Uploa
var url = string.Format(Config.ApiWorkHost + "/cgi-bin/media/upload?access_token={0}&type={1}", accessToken.AsUrlData(), type.ToString());
var fileDictionary = new Dictionary();
fileDictionary["media"] = media;
- return CO2NET.HttpUtility.Post.PostFileGetJson(CommonDI.CommonSP, url, null, fileDictionary, null, null, null, false, timeOut: timeOut);
+ return CO2NET.HttpUtility.Post.PostFileGetJson(CommonDI.CommonSP, url, null, fileDictionary, timeOut: timeOut);
}, accessTokenOrAppKey);
-
-
}
///
@@ -96,9 +94,6 @@ public static void Get(string accessTokenOrAppKey, string mediaId, Stream stream
return new WorkJsonResult() { errcode = ReturnCode_Work.请求成功, errmsg = "ok" };
}, accessTokenOrAppKey);
-
-
-
}
///
/// 获取临时媒体文件并保存到指定目录中
@@ -171,8 +166,6 @@ public static UploadForeverResultJson AddMpNews(string accessTokenOrAppKey, int
return CommonJsonSend.Send(null, url, data, CommonJsonSendType.POST, timeOut);
}, accessTokenOrAppKey);
-
-
}
///
@@ -191,10 +184,8 @@ public static UploadForeverResultJson AddMaterial(string accessTokenOrAppKey, Up
var url = string.Format(Config.ApiWorkHost + "/cgi-bin/material/add_material?agentid={1}&type={2}&access_token={0}", accessToken.AsUrlData(), agentId, type);
var fileDictionary = new Dictionary();
fileDictionary["media"] = media;
- return Post.PostFileGetJson(CommonDI.CommonSP, url, null, fileDictionary, null, null, null, false, null, timeOut: timeOut);
+ return Post.PostFileGetJson(CommonDI.CommonSP, url, null, fileDictionary, null, null, null, timeOut: timeOut);
}, accessTokenOrAppKey);
-
-
}
///
@@ -215,8 +206,6 @@ public static GetForeverMpNewsResult GetForeverMpNews(string accessTokenOrAppKey
return CommonJsonSend.Send(null, url, null, CommonJsonSendType.GET);
}, accessTokenOrAppKey);
-
-
}
///
@@ -259,8 +248,6 @@ public static WorkJsonResult DeleteForeverMaterial(string accessTokenOrAppKey, i
return CommonJsonSend.Send(null, url, null, CommonJsonSendType.GET);
}, accessTokenOrAppKey);
-
-
}
///
@@ -291,8 +278,6 @@ public static UploadForeverResultJson UpdateMpNews(string accessTokenOrAppKey, s
return CommonJsonSend.Send(null, url, data, CommonJsonSendType.POST, timeOut);
}, accessTokenOrAppKey);
-
-
}
///
@@ -310,8 +295,6 @@ public static GetCountResult GetCount(string accessTokenOrAppKey, int agentId)
return CommonJsonSend.Send(null, url, null, CommonJsonSendType.GET);
}, accessTokenOrAppKey);
-
-
}
///
@@ -341,9 +324,8 @@ public static BatchGetMaterialResult BatchGetMaterial(string accessTokenOrAppKey
return CommonJsonSend.Send(null, url, data, CommonJsonSendType.POST, timeOut);
}, accessTokenOrAppKey);
-
-
}
+
///
/// 上传图文消息内的图片
/// 上传的图片限制:大小不超过2MB,支持JPG,PNG格式,每天上传的图片不能超过100张
@@ -365,8 +347,6 @@ public static UploadimgMediaResult UploadimgMedia(string accessTokenOrAppKey, st
return Post.PostFileGetJson(CommonDI.CommonSP, url, null, fileDictionary, null, timeOut: timeOut);
}, accessTokenOrAppKey);
-
-
}
#endregion
@@ -388,10 +368,8 @@ public static async Task UploadAsync(string accessTok
var url = string.Format(Config.ApiWorkHost + "/cgi-bin/media/upload?access_token={0}&type={1}", accessToken.AsUrlData(), type.ToString());
var fileDictionary = new Dictionary();
fileDictionary["media"] = media;
- return await Post.PostFileGetJsonAsync(CommonDI.CommonSP, url, null, fileDictionary, null, null, null, false, null, timeOut: timeOut).ConfigureAwait(false);
+ return await Post.PostFileGetJsonAsync(CommonDI.CommonSP, url, null, fileDictionary, timeOut: timeOut).ConfigureAwait(false);
}, accessTokenOrAppKey).ConfigureAwait(false);
-
-
}
///
@@ -410,8 +388,6 @@ await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
await CO2NET.HttpUtility.Get.DownloadAsync(CommonDI.CommonSP, url, stream).ConfigureAwait(false);//todo 异常处理
return new WorkJsonResult() { errcode = ReturnCode_Work.请求成功, errmsg = "ok" };
}, accessTokenOrAppKey).ConfigureAwait(false);
-
-
}
///
@@ -440,8 +416,6 @@ public static async Task AddMpNewsAsync(string accessTo
return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(null, url, data, CommonJsonSendType.POST, timeOut).ConfigureAwait(false);
}, accessTokenOrAppKey).ConfigureAwait(false);
-
-
}
///
@@ -460,10 +434,8 @@ public static async Task AddMaterialAsync(string access
var url = string.Format(Config.ApiWorkHost + "/cgi-bin/material/add_material?agentid={1}&type={2}&access_token={0}", accessToken.AsUrlData(), agentId, type);
var fileDictionary = new Dictionary();
fileDictionary["media"] = media;
- return await Post.PostFileGetJsonAsync(CommonDI.CommonSP, url, null, fileDictionary, null, null, null, false, null, timeOut: timeOut).ConfigureAwait(false);
+ return await Post.PostFileGetJsonAsync(CommonDI.CommonSP, url, null, fileDictionary, timeOut: timeOut).ConfigureAwait(false);
}, accessTokenOrAppKey).ConfigureAwait(false);
-
-
}
///
@@ -484,7 +456,6 @@ public static async Task GetForeverMpNewsAsync(string ac
return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(null, url, null, CommonJsonSendType.GET).ConfigureAwait(false);
}, accessTokenOrAppKey).ConfigureAwait(false);
-
}
///
@@ -508,8 +479,6 @@ await ApiHandlerWapper.TryCommonApiAsync(async accessToken =>
return new WorkJsonResult() { errcode = ReturnCode_Work.请求成功, errmsg = "ok" };
}, accessTokenOrAppKey).ConfigureAwait(false);
-
-
}
///
@@ -530,8 +499,6 @@ public static async Task DeleteForeverMaterialAsync(string acces
return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(null, url, null, CommonJsonSendType.GET).ConfigureAwait(false);
}, accessTokenOrAppKey).ConfigureAwait(false);
-
-
}
///
@@ -562,8 +529,6 @@ public static async Task UpdateMpNewsAsync(string acces
return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(null, url, data, CommonJsonSendType.POST, timeOut).ConfigureAwait(false);
}, accessTokenOrAppKey).ConfigureAwait(false);
-
-
}
///
@@ -581,8 +546,6 @@ public static async Task GetCountAsync(string accessTokenOrAppKe
return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(null, url, null, CommonJsonSendType.GET).ConfigureAwait(false);
}, accessTokenOrAppKey).ConfigureAwait(false);
-
-
}
///
@@ -612,8 +575,6 @@ public static async Task BatchGetMaterialAsync(string ac
return await Senparc.Weixin.CommonAPIs.CommonJsonSend.SendAsync(null, url, data, CommonJsonSendType.POST, timeOut).ConfigureAwait(false);
}, accessTokenOrAppKey).ConfigureAwait(false);
-
-
}
///
@@ -631,13 +592,10 @@ public static async Task UploadimgMediaAsync(string access
var url = string.Format(Config.ApiWorkHost + "/cgi-bin/media/uploadimg?access_token={0}",
accessToken.AsUrlData());
-
var fileDictionary = new Dictionary();
fileDictionary["media"] = imgFile;
return await Post.PostFileGetJsonAsync(CommonDI.CommonSP, url, null, fileDictionary, null, timeOut: timeOut).ConfigureAwait(false);
}, accessTokenOrAppKey).ConfigureAwait(false);
-
-
}
#endregion
}
diff --git a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.net8.csproj b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.net8.csproj
index 92d8e77a0d..efbec5df1d 100644
--- a/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.net8.csproj
+++ b/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Senparc.Weixin.Work.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1
- 3.25.1
+ 3.25.2
10.0
Senparc.Weixin.Work
Senparc.Weixin.Work
@@ -258,7 +258,7 @@
-
+
diff --git a/src/Senparc.Weixin.WxOpen.Middleware/Senparc.Weixin.WxOpen.Middleware.net8.csproj b/src/Senparc.Weixin.WxOpen.Middleware/Senparc.Weixin.WxOpen.Middleware.net8.csproj
index d163c6eee5..5052a0086e 100644
--- a/src/Senparc.Weixin.WxOpen.Middleware/Senparc.Weixin.WxOpen.Middleware.net8.csproj
+++ b/src/Senparc.Weixin.WxOpen.Middleware/Senparc.Weixin.WxOpen.Middleware.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1;netcoreapp3.1;net8.0
- 1.4.6
+ 1.4.7
Senparc.Weixin.WxOpen.Middleware
Senparc.Weixin.WxOpen.Middleware
true
@@ -69,7 +69,7 @@
-
+
diff --git a/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen.Tests/Senparc.Weixin.WxOpen.Tests.net8.csproj b/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen.Tests/Senparc.Weixin.WxOpen.Tests.net8.csproj
index 92a0379f67..7e919c6376 100644
--- a/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen.Tests/Senparc.Weixin.WxOpen.Tests.net8.csproj
+++ b/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen.Tests/Senparc.Weixin.WxOpen.Tests.net8.csproj
@@ -35,7 +35,7 @@
-
+
diff --git a/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen.net8.csproj b/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen.net8.csproj
index 216b724a27..c7cae05601 100644
--- a/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen.net8.csproj
+++ b/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen.net8.csproj
@@ -1,7 +1,7 @@
net462;netstandard2.0;netstandard2.1
- 3.23.1
+ 3.23.2
9.0
Senparc.Weixin.WxOpen
Senparc.Weixin.WxOpen
@@ -225,7 +225,7 @@
-
+
diff --git a/src/Senparc.Weixin/Senparc.Weixin/Entities/SenparcWeixinSettings/SenparcWeixinSettingItem.Interfaces.cs b/src/Senparc.Weixin/Senparc.Weixin/Entities/SenparcWeixinSettings/SenparcWeixinSettingItem.Interfaces.cs
index 023b7cf1a3..bf4346c727 100644
--- a/src/Senparc.Weixin/Senparc.Weixin/Entities/SenparcWeixinSettings/SenparcWeixinSettingItem.Interfaces.cs
+++ b/src/Senparc.Weixin/Senparc.Weixin/Entities/SenparcWeixinSettings/SenparcWeixinSettingItem.Interfaces.cs
@@ -223,6 +223,18 @@ public interface ISenparcWeixinSettingForTenpayV3 : ISenparcWeixinSettingBase
///
string TenPayV3_APIv3Key { get; set; }
+ ///
+ /// 微信支付(V3)微信平台公钥(替换平台证书)
+ ///
+ string TenPayV3_TenPayPubKey { get; set; }
+ ///
+ /// 微信支付(V3)微信平台公钥ID(替换平台证书)
+ ///
+ string TenPayV3_TenPayPubKeyID { get; set; }
+ ///
+ /// 微信支付(V3)微信平台公钥 启动
+ ///
+ bool TenPayV3_TenPayPubKeyEnable { get; set; }
#endregion
///
diff --git a/src/Senparc.Weixin/Senparc.Weixin/Entities/SenparcWeixinSettings/SenparcWeixinSettingItem.cs b/src/Senparc.Weixin/Senparc.Weixin/Entities/SenparcWeixinSettings/SenparcWeixinSettingItem.cs
index 113b248984..7ab5420f6c 100644
--- a/src/Senparc.Weixin/Senparc.Weixin/Entities/SenparcWeixinSettings/SenparcWeixinSettingItem.cs
+++ b/src/Senparc.Weixin/Senparc.Weixin/Entities/SenparcWeixinSettings/SenparcWeixinSettingItem.cs
@@ -131,6 +131,9 @@ public SenparcWeixinSettingItem(ISenparcWeixinSettingForTenpayV3 setting, bool i
TenPayV3_APIv3Key = setting.TenPayV3_APIv3Key;
TenPayV3_PrivateKey = setting.TenPayV3_PrivateKey;
TenPayV3_SerialNumber = setting.TenPayV3_SerialNumber;
+
+ TenPayV3_TenPayPubKey = setting.TenPayV3_TenPayPubKey;
+
TenPayV3_WxOpenTenpayNotify = setting.TenPayV3_WxOpenTenpayNotify;
}
@@ -321,7 +324,42 @@ public virtual string TenPayV3_PrivateKey
///
/// APIv3 密钥。在微信支付后台设置:https://pay.weixin.qq.com/index.php/core/cert/api_cert#/
///
- public string TenPayV3_APIv3Key { get; set; }
+ public virtual string TenPayV3_APIv3Key { get; set; }
+
+
+ private string _tenPayV3_WeixinPubKey;
+ ///
+ /// 微信支付(V3)公钥证书(替换平台证书)
+ ///
+ public virtual string TenPayV3_TenPayPubKey
+ {
+ get
+ {
+ return TenPayHelper.TryGetPublicKeyFromFile(ref _tenPayV3_WeixinPubKey);
+ }
+ set
+ {
+ _tenPayV3_WeixinPubKey = value;
+ }
+ }
+
+ ///
+ /// 微信支付(V3)公钥证书序列号(替换平台证书)
+ ///
+ public virtual string TenPayV3_TenPayPubKeyID { get; set; }
+
+ ///
+ /// 微信支付(V3)公钥证书 是否启用
+ ///
+ public virtual bool TenPayV3_TenPayPubKeyEnable
+ {
+ get
+ {
+ return !string.IsNullOrWhiteSpace(TenPayV3_TenPayPubKey) && !string.IsNullOrWhiteSpace(TenPayV3_TenPayPubKeyID);
+ }
+ set { }
+
+ }
#endregion
///
diff --git a/src/Senparc.Weixin/Senparc.Weixin/Helpers/TenPay/TenPayHelper.cs b/src/Senparc.Weixin/Senparc.Weixin/Helpers/TenPay/TenPayHelper.cs
index 452794b0c9..6be9be0de0 100644
--- a/src/Senparc.Weixin/Senparc.Weixin/Helpers/TenPay/TenPayHelper.cs
+++ b/src/Senparc.Weixin/Senparc.Weixin/Helpers/TenPay/TenPayHelper.cs
@@ -84,5 +84,29 @@ public static string TryGetPrivateKeyFromFile(ref string tenPayV3_PrivateKey)
}
return tenPayV3_PrivateKey;
}
+
+ ///
+ /// 尝试从文件获取正确格式的私钥
+ ///
+ ///
+ public static string TryGetPublicKeyFromFile(ref string tenPayV3_PubKey)
+ {
+ if (tenPayV3_PubKey != null && tenPayV3_PubKey.Length < 100 && tenPayV3_PubKey.StartsWith("~/"))
+ {
+ //虚拟路径
+ //尝试读取文件
+ var filePath = CO2NET.Utilities.ServerUtility.ContentRootMapPath(tenPayV3_PubKey);
+ if (!File.Exists(filePath))
+ {
+ Senparc.Weixin.WeixinTrace.BaseExceptionLog(new WeixinException("TenPayV3_PubKey 证书文件不存在!" + filePath));
+ }
+
+ var fileContent = File.ReadAllText(filePath);
+ Regex regex = new Regex(@"(--([^\r\n])+--[\r\n]{0,1})|[\r\n]");
+ var publicKey = regex.Replace(fileContent, "");
+ tenPayV3_PubKey = publicKey;
+ }
+ return tenPayV3_PubKey;
+ }
}
}
diff --git a/src/Senparc.Weixin/Senparc.Weixin/Senparc.Weixin.net8.csproj b/src/Senparc.Weixin/Senparc.Weixin/Senparc.Weixin.net8.csproj
index 2121bb3a11..70353fdb32 100644
--- a/src/Senparc.Weixin/Senparc.Weixin/Senparc.Weixin.net8.csproj
+++ b/src/Senparc.Weixin/Senparc.Weixin/Senparc.Weixin.net8.csproj
@@ -2,7 +2,7 @@
net462;netstandard2.0;netstandard2.1
- 6.21.2
+ 6.21.3
10.0
Senparc.Weixin
Senparc.Weixin
@@ -381,8 +381,8 @@
-
-
+
+
@@ -398,10 +398,6 @@
-
-
-
-
diff --git a/src/Senparc.Weixin/Senparc.WeixinTests/Senparc.WeixinTests.net8.csproj b/src/Senparc.Weixin/Senparc.WeixinTests/Senparc.WeixinTests.net8.csproj
index d2f3adb172..c7ef3803fc 100644
--- a/src/Senparc.Weixin/Senparc.WeixinTests/Senparc.WeixinTests.net8.csproj
+++ b/src/Senparc.Weixin/Senparc.WeixinTests/Senparc.WeixinTests.net8.csproj
@@ -27,7 +27,7 @@
-
+