diff --git a/Admin.NET/Admin.NET.Application/Configuration/Alipay.json b/Admin.NET/Admin.NET.Application/Configuration/Alipay.json
index 3c1e24fc..585b9af3 100644
--- a/Admin.NET/Admin.NET.Application/Configuration/Alipay.json
+++ b/Admin.NET/Admin.NET.Application/Configuration/Alipay.json
@@ -3,16 +3,33 @@
// 支付宝支付配置,文档地址:https://openhome.alipay.com/develop/sandbox/app
"Alipay": {
- "AppId": "9000000000000000", // 支付宝 APPID
- "AlipayWebsocketUrl": "openchannel-sandbox.dl.alipaydev.com", // websocket服务地址
"ServerUrl": "https://openapi-sandbox.dl.alipaydev.com/gateway.do", // 支付宝网关地址
- "AuthUrl": "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm", // 授权回调地址
- "NotifyUrl": "http://xxxx.xxx/api/Alipay/Notify", // 应用网关地址
- "PrivateKey": "xxxxxxxxx", // 应用私钥
- "SignType": "RSA2", // 加密算法
- "EncryptKey": "xxxxxxxx", // 从支付宝获取敏感信息时的加密密钥
- "AlipayPublicCertPath": "/AlipayCrt/alipayPublicCert.crt", // 支付宝公钥证书存放路径
- "RootCertPath": "/AlipayCrt/alipayRootCert.crt", // 支付宝根证书存放路径
- "AppCertPath": "/AlipayCrt/appPublicCert.crt" // 应用公钥证书存放路径
+ "WebsocketUrl": "openchannel-sandbox.dl.alipaydev.com", // websocket服务地址
+ //"AuthUrl": "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm", // 正式环境授权回调地址
+ "AuthUrl": "https://openauth-sandbox.dl.alipaydev.com/oauth2/publicAppAuthorize.htm", // 沙箱环境授权回调地址
+ "AppAuthUrl": "http://xxxxxxxxxx", // 应用授权回调地址
+ "NotifyUrl": "http://xxxxxxxxx/api/sysAlipay/Notify", // 应用网关地址
+ "RootCertPath": "Alipaycrt/alipayRootCert.crt", // 支付宝根证书存放路径
+ "AccountList": [
+ {
+ "Name": "sandbox 默认应用",
+ "AppId": "xxxxxxxxxxxxxx",
+ "SignType": "RSA2",
+ "PrivateKey": "xxxxxxxxxxxxxxxxx",
+ "EncryptKey": "xxxxxxxxxxxxxxxxxxxx",
+ "AppCertPath": "Alipaycrt/appPublicCert.crt", // 应用公钥证书存放路径
+ "AlipayPublicCertPath": "Alipaycrt/alipayPublicCert.crt" // 支付宝公钥证书存放路径
+
+ },
+ {
+ "Name": "sandbox 默认应用2",
+ "AppId": "xxxxxxxxxxxxxx",
+ "SignType": "RSA2",
+ "PrivateKey": "xxxxxxxxxxxxxxxxx",
+ "EncryptKey": "xxxxxxxxxxxxxxxxxxxx",
+ "AppCertPath": "Alipaycrt/appPublicCert.crt", // 应用公钥证书存放路径
+ "AlipayPublicCertPath": "Alipaycrt/alipayPublicCert.crt" // 支付宝公钥证书存放路径
+ }
+ ]
}
}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysAlipayAuthInfo.cs b/Admin.NET/Admin.NET.Core/Entity/SysAlipayAuthInfo.cs
new file mode 100644
index 00000000..3c2aa307
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysAlipayAuthInfo.cs
@@ -0,0 +1,149 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 支付宝授权记录表
+///
+[SysTable]
+[SugarTable(null, "支付宝授权记录表")]
+[SugarIndex("index_{table}_U", nameof(UserId), OrderByType.Asc)]
+[SugarIndex("index_{table}_T", nameof(OpenId), OrderByType.Asc)]
+public class SysAlipayAuthInfo : EntityBase
+{
+ ///
+ /// 商户AppId
+ ///
+ [SugarColumn(ColumnDescription = "商户AppId", Length = 64)]
+ public string? AppId { get; set; }
+
+ ///
+ /// 开放ID
+ ///
+ [SugarColumn(ColumnDescription = "开放ID", Length = 64)]
+ public string? OpenId { get; set; }
+
+ ///
+ /// 用户ID
+ ///
+ [SugarColumn(ColumnDescription = "用户ID", Length = 64)]
+ public string? UserId { get; set; }
+
+ ///
+ /// 性别
+ ///
+ [SugarColumn(ColumnDescription = "性别", Length = 8)]
+ public GenderEnum Gender { get; set; }
+
+ ///
+ /// 年龄
+ ///
+ [SugarColumn(ColumnDescription = "年龄", Length = 16)]
+ public int Age { get; set; }
+
+ ///
+ /// 手机号
+ ///
+ [SugarColumn(ColumnDescription = "手机号", Length = 32)]
+ public string Mobile { get; set; }
+
+ ///
+ /// 显示名称
+ ///
+ [SugarColumn(ColumnDescription = "显示名称", Length = 128)]
+ public string DisplayName { get; set; }
+
+ ///
+ /// 昵称
+ ///
+ [SugarColumn(ColumnDescription = "昵称", Length = 64)]
+ public string NickName { get; set; }
+
+ ///
+ /// 用户名
+ ///
+ [SugarColumn(ColumnDescription = "用户名", Length = 64)]
+ public string UserName { get; set; }
+
+ ///
+ /// 头像
+ ///
+ [SugarColumn(ColumnDescription = "头像", Length = 512)]
+ public string? Avatar { get; set; }
+
+ ///
+ /// 邮箱
+ ///
+ [SugarColumn(ColumnDescription = "邮箱", Length = 128)]
+ public string? Email { get; set; }
+
+ ///
+ /// 用户民族
+ ///
+ [SugarColumn(ColumnDescription = "用户民族", Length = 32)]
+ public string? UserNation { get; set; }
+
+ ///
+ /// 淘宝ID
+ ///
+ [SugarColumn(ColumnDescription = "淘宝ID", Length = 64)]
+ public string? TaobaoId { get; set; }
+
+ ///
+ /// 电话
+ ///
+ [SugarColumn(ColumnDescription = "电话", Length = 32)]
+ public string? Phone { get; set; }
+
+ ///
+ /// 生日
+ ///
+ [SugarColumn(ColumnDescription = "生日", Length = 32)]
+ public string? PersonBirthday { get; set; }
+
+ ///
+ /// 职业
+ ///
+ [SugarColumn(ColumnDescription = "职业", Length = 64)]
+ public string? Profession { get; set; }
+
+ ///
+ /// 省份
+ ///
+ [SugarColumn(ColumnDescription = "省份", Length = 64)]
+ public string? Province { get; set; }
+
+ ///
+ /// 用户状态
+ ///
+ [SugarColumn(ColumnDescription = "用户状态", Length = 32)]
+ public string? UserStatus { get; set; }
+
+ ///
+ /// 学历
+ ///
+ [SugarColumn(ColumnDescription = "学历", Length = 32)]
+ public string? Degree { get; set; }
+
+ ///
+ /// 用户类型
+ ///
+ [SugarColumn(ColumnDescription = "用户类型", Length = 32)]
+ public string? UserType { get; set; }
+
+ ///
+ /// 邮编
+ ///
+ [SugarColumn(ColumnDescription = "邮编", Length = 16)]
+ public string? Zip { get; set; }
+
+ ///
+ /// 地址
+ ///
+ [SugarColumn(ColumnDescription = "地址", Length = 256)]
+ public string? Address { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Entity/SysAlipayTransaction.cs b/Admin.NET/Admin.NET.Core/Entity/SysAlipayTransaction.cs
new file mode 100644
index 00000000..5ca95bcf
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Entity/SysAlipayTransaction.cs
@@ -0,0 +1,108 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+///
+/// 支付宝交易记录表
+///
+[SysTable]
+[SugarTable(null, "支付宝交易记录表")]
+[SugarIndex("index_{table}_U", nameof(UserId), OrderByType.Asc)]
+[SugarIndex("index_{table}_T", nameof(TradeNo), OrderByType.Asc)]
+[SugarIndex("index_{table}_O", nameof(OutTradeNo), OrderByType.Asc)]
+public class SysAlipayTransaction : EntityBase
+{
+ ///
+ /// 用户Id
+ ///
+ [SugarColumn(ColumnDescription = "用户Id", Length = 64)]
+ public long UserId { get; set; }
+
+ ///
+ /// 交易号
+ ///
+ [SugarColumn(ColumnDescription = "交易号", Length = 64)]
+ public string? TradeNo { get; set; }
+
+ ///
+ /// 商户订单号
+ ///
+ [SugarColumn(ColumnDescription = "商户订单号", Length = 64)]
+ public string OutTradeNo { get; set; }
+
+ ///
+ /// 交易金额
+ ///
+ [SugarColumn(ColumnDescription = "交易金额", Length = 20)]
+ public decimal TotalAmount { get; set; }
+
+ ///
+ /// 交易状态
+ ///
+ [SugarColumn(ColumnDescription = "交易状态", Length = 32)]
+ public string TradeStatus { get; set; }
+
+ ///
+ /// 交易完成时间
+ ///
+ [SugarColumn(ColumnDescription = "交易完成时间")]
+ public DateTime? FinishTime { get; set; }
+
+ ///
+ /// 交易标题
+ ///
+ [SugarColumn(ColumnDescription = "交易标题", Length = 256)]
+ public string Subject { get; set; }
+
+ ///
+ /// 交易描述
+ ///
+ [SugarColumn(ColumnDescription = "交易描述", Length = 512)]
+ public string? Body { get; set; }
+
+ ///
+ /// 买家支付宝账号
+ ///
+ [SugarColumn(ColumnDescription = "买家支付宝账号", Length = 128)]
+ public string? BuyerLogonId { get; set; }
+
+ ///
+ /// 买家支付宝用户ID
+ ///
+ [SugarColumn(ColumnDescription = "买家支付宝用户ID", Length = 32)]
+ public string? BuyerUserId { get; set; }
+
+ ///
+ /// 卖家支付宝用户ID
+ ///
+ [SugarColumn(ColumnDescription = "卖家支付宝用户ID", Length = 32)]
+ public string? SellerUserId { get; set; }
+
+ ///
+ /// 商户AppId
+ ///
+ [SugarColumn(ColumnDescription = "商户AppId", Length = 64)]
+ public string? AppId { get; set; }
+
+ ///
+ /// 交易扩展信息
+ ///
+ [SugarColumn(ColumnDescription = "交易扩展信息", Length = 1024)]
+ public string? ExtendInfo { get; set; }
+
+ ///
+ /// 交易异常信息
+ ///
+ [SugarColumn(ColumnDescription = "交易扩展信息", Length = 1024)]
+ public string? ErrorInfo { get; set; }
+
+ ///
+ /// 交易备注
+ ///
+ [SugarColumn(ColumnDescription = "交易备注", Length = 512)]
+ public string? Remark { get; set; }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Option/AlipayOptions.cs b/Admin.NET/Admin.NET.Core/Option/AlipayOptions.cs
index 2ece6bb6..ddd1bb02 100644
--- a/Admin.NET/Admin.NET.Core/Option/AlipayOptions.cs
+++ b/Admin.NET/Admin.NET.Core/Option/AlipayOptions.cs
@@ -4,6 +4,8 @@
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+using Aop.Api;
+
namespace Admin.NET.Core;
///
@@ -12,57 +14,106 @@ namespace Admin.NET.Core;
public sealed class AlipayOptions : IConfigurableOptions
{
///
- /// 支付宝 APPID(必填)
+ /// 支付宝网关地址
///
- public string AppId { get; set; }
+ public string ServerUrl { get; init; }
///
- /// 支付宝 websocket 服务地址 (必填)
+ /// 支付宝授权回调地址
///
- public string AlipayWebsocketUrl { get; set; }
+ public string AuthUrl { get; init; }
///
- /// 支付宝网关地址 (必填)
+ /// 应用授权回调地址
///
- public string ServerUrl { get; set; }
+ public string AppAuthUrl { get; init; }
///
- /// 支付宝授权回调地址 (必填)
+ /// 支付宝 websocket 服务地址
///
- public string AuthUrl { get; set; }
+ public string WebsocketUrl { get; init; }
///
/// 应用回调地址
///
- public string NotifyUrl { get; set; }
+ public string NotifyUrl { get; init; }
///
- /// 加密算法(必填)
+ /// 支付宝根证书存放路径
///
- public string SignType { get; set; }
+ public string RootCertPath { get; init; }
+
+ ///
+ /// 支付宝商户账号列表
+ ///
+ public List AccountList { get; init; }
+
+ ///
+ /// 获取支付宝客户端
+ ///
+ ///
+ public DefaultAopClient GetClient(AlipayMerchantAccount account)
+ {
+ account = account ?? throw new Exception("未找到支付宝商户账号");
+ string path = App.WebHostEnvironment.ContentRootPath;
+ return new DefaultAopClient(new AlipayConfig
+ {
+ Format = "json",
+ Charset = "UTF-8",
+ ServerUrl = ServerUrl,
+ AppId = account.AppId,
+ SignType = account.SignType,
+ PrivateKey = account.PrivateKey,
+ EncryptKey = account.EncryptKey,
+ RootCertPath = Path.Combine(path, RootCertPath),
+ AppCertPath = Path.Combine(path, account.AppCertPath),
+ AlipayPublicCertPath = Path.Combine(path, account.AlipayPublicCertPath)
+ });
+ }
+}
+
+///
+/// 支付宝商户账号信息
+///
+public class AlipayMerchantAccount
+{
+ ///
+ /// 配置Id
+ ///
+ public long Id { get; init; }
+
+ ///
+ /// 商户名称
+ ///
+ public string Name { get; init; }
+
+ ///
+ /// 商户AppId
+ ///
+ public string AppId { get; init; }
+
+ ///
+ /// 应用私钥
+ ///
+ public string PrivateKey { get; init; }
///
/// 从支付宝获取敏感信息时的加密密钥(可选)
///
- public string EncryptKey { get; set; }
+ public string EncryptKey { get; init; }
///
- /// 应用私钥 (必填)
+ /// 加密算法
///
- public string PrivateKey { get; set; }
+ public string SignType { get; init; }
///
- /// 支付宝公钥证书存放路径(证书加签方式必填)
+ /// 应用公钥证书路径
///
- public string AlipayPublicCertPath { get; set; }
+ public string AppCertPath { get; init; }
///
- /// 支付宝根证书存放路径(证书加签方式必填)
+ /// 支付宝公钥证书路径
///
- public string RootCertPath { get; set; }
-
- ///
- /// 应用公钥证书存放路径(证书加签方式必填)
- ///
- public string AppCertPath { get; set; }
+ public string AlipayPublicCertPath { get; init; }
}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Service/Alipay/AlipayService.cs b/Admin.NET/Admin.NET.Core/Service/Alipay/AlipayService.cs
deleted file mode 100644
index 90f3f409..00000000
--- a/Admin.NET/Admin.NET.Core/Service/Alipay/AlipayService.cs
+++ /dev/null
@@ -1,279 +0,0 @@
-// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
-//
-// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
-//
-// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
-
-using Aop.Api;
-using Aop.Api.Domain;
-using Aop.Api.Request;
-using Aop.Api.Response;
-using Aop.Api.Util;
-using Microsoft.AspNetCore.Hosting;
-
-namespace Admin.NET.Core.Service;
-
-///
-/// 支付宝支付服务 🧩
-///
-[ApiDescriptionSettings(Order = 240)]
-public class AlipayService : IDynamicApiController, ITransient
-{
- private readonly IEnumerable _alipayNotifyList;
- private readonly IWebHostEnvironment _webHostEnvironment;
- private readonly SysConfigService _sysConfigService;
- private readonly IHttpContextAccessor _httpContext;
- private readonly AlipayOptions _alipayOptions;
- private readonly IAopClient _alipayClient;
- private readonly UserManager _userManager;
-
- public AlipayService(
- UserManager userManager,
- IHttpContextAccessor httpContext,
- SysConfigService sysConfigService,
- IWebHostEnvironment webHostEnvironment,
- IOptions alipayOptions)
- {
- _userManager = userManager;
- _httpContext = httpContext;
- _sysConfigService = sysConfigService;
- _alipayOptions = alipayOptions.Value;
- _webHostEnvironment = webHostEnvironment;
- _alipayNotifyList = App.GetServices();
-
- // 初始化支付宝客户端
- string path = App.WebHostEnvironment.ContentRootPath;
- _alipayClient = new DefaultAopClient(new AlipayConfig
- {
- Format = "json",
- Charset = "UTF-8",
- AppId = _alipayOptions.AppId,
- SignType = _alipayOptions.SignType,
- ServerUrl = _alipayOptions.ServerUrl,
- PrivateKey = _alipayOptions.PrivateKey,
- EncryptKey = _alipayOptions.EncryptKey,
- AppCertPath = Path.Combine(path, _alipayOptions.AppCertPath),
- RootCertPath = Path.Combine(path, _alipayOptions.RootCertPath),
- AlipayPublicCertPath = Path.Combine(path, _alipayOptions.AlipayPublicCertPath)
- });
- }
-
- ///
- /// 获取授权信息 🔖
- ///
- ///
- ///
- [NonUnify]
- [AllowAnonymous]
- [DisplayName("获取授权信息")]
- [ApiDescriptionSettings(Name = "GetAuthInfo"), HttpGet]
- public ActionResult GetAuthInfo([FromQuery] AlipayAuthInfoInput input)
- {
- var type = input.UserId.Split('-').FirstOrDefault().ToInt();
- var userId = input.UserId.Split('-').LastOrDefault().ToLong();
-
- // 当前网页接口地址
- var currentUrl = $"{_httpContext.HttpContext!.Request.GetOrigin()}{_httpContext.HttpContext!.Request.Path}?userId={input.UserId}";
- if (string.IsNullOrEmpty(input.AuthCode))
- {
- // 重新授权
- var url = $"{_alipayOptions.AuthUrl}?app_id={_alipayOptions.AppId}&scope=auth_user&redirect_uri={currentUrl}";
- return new RedirectResult(url);
- }
-
- // 组装授权请求参数
- AlipaySystemOauthTokenRequest request = new()
- {
- GrantType = AlipayConst.GrantType,
- Code = input.AuthCode
- };
- AlipaySystemOauthTokenResponse response = _alipayClient.CertificateExecute(request);
-
- // token换取用户信息
- AlipayUserInfoShareRequest infoShareRequest = new();
- AlipayUserInfoShareResponse info = _alipayClient.CertificateExecute(infoShareRequest, response.AccessToken);
-
- // 循环执行扫码后需要执行的业务逻辑,需要至少一个继承方法返回true,否则抛出异常
- var pass = false;
- foreach (var notify in _alipayNotifyList)
- if (notify.ScanCallback(type, userId, info)) pass = true;
- if (!pass) throw Oops.Oh("未处理的授权逻辑");
-
- // 执行完,重定向到指定界面
- var authPageUrl = _sysConfigService.GetConfigValueByCode(ConfigConst.AlipayAuthPageUrl + type).Result;
- return new RedirectResult(authPageUrl);
- }
-
- ///
- /// 支付回调 🔖
- ///
- ///
- [AllowAnonymous]
- [DisplayName("支付回调")]
- [ApiDescriptionSettings(Name = "Notify"), HttpPost]
- public string Notify()
- {
- SortedDictionary sorted = [];
- foreach (string key in _httpContext.HttpContext!.Request.Form.Keys)
- sorted.Add(key, _httpContext.HttpContext.Request.Form[key]);
-
- string alipayPublicKey = Path.Combine(_webHostEnvironment.ContentRootPath, _alipayOptions.AlipayPublicCertPath!.Replace('/', '\\').TrimStart('\\'));
- bool signVerified = AlipaySignature.RSACertCheckV1(sorted, alipayPublicKey, "UTF-8", _alipayOptions.SignType); // 调用SDK验证签名
- if (!signVerified) throw Oops.Oh("交易失败");
-
- var outTradeNo = sorted.GetValueOrDefault("out_trade_no");
- try
- {
- // 记录回调日志
- File.AppendAllText($"{_webHostEnvironment.ContentRootPath}\\AlipayLog\\Notify-{DateTime.Today:yyyy-MM-dd}.txt",
- $"支付宝支付到平台({DateTime.Now:yyyy-MM-dd HH:mm:ss}):{Environment.NewLine} " +
- $"登录人:{_userManager.UserId}-{_userManager.RealName}{Environment.NewLine} " +
- $"IP:{App.HttpContext?.GetRemoteIpAddressToIPv4(true)} {Environment.NewLine} " +
- $"交易号:{outTradeNo}{Environment.NewLine} " +
- $"参数:{JSON.Serialize(sorted)}{Environment.NewLine} " +
- $"-----------------------------------------------------------------------------------------------------------------------" +
- $"{Environment.NewLine}{Environment.NewLine}{Environment.NewLine}");
- }
- catch (Exception ex)
- {
- Log.Error("支付宝支付回调日志写入失败:", ex);
- }
-
- if (sorted.GetValueOrDefault(AlipayConst.TradeStatus) == AlipayConst.TradeSuccess)
- {
- // 约定交易码前四位为类型码,后面为订单号
- var tradeNo = long.Parse(outTradeNo);
- var type = long.Parse(outTradeNo[..4]);
-
- // 循环执行业务逻辑,若都未处理(回调全部返回false)则交易失败
- var isError = true;
- foreach (var notify in _alipayNotifyList)
- if (notify.TopUpCallback(type, tradeNo)) isError = false;
- if (isError) throw Oops.Oh("交易失败");
- }
- return "success";
- }
-
- ///
- /// 统一收单下单并支付页面接口 🔖
- ///
- ///
- ///
- [DisplayName("统一收单下单并支付页面接口")]
- [ApiDescriptionSettings(Name = "AlipayTradePagePay"), HttpPost]
- public string AlipayTradePagePay(AlipayTradePagePayInput input)
- {
- AlipayTradeWapPayRequest request = new();
-
- // 组装业务参数model
- AlipayTradeWapPayModel model = new()
- {
- Subject = input.Subject,
- OutTradeNo = input.OutTradeNo,
- TotalAmount = input.TotalAmount,
- Body = input.Body,
- ProductCode = "QUICK_WAP_WAY",
- TimeExpire = input.TimeoutExpress
- };
- request.SetBizModel(model);
-
- // 设置异步通知接收地址
- request.SetNotifyUrl(_alipayOptions.NotifyUrl);
-
- var response = _alipayClient.SdkExecute(request);
- if (response.IsError) throw Oops.Oh(response.SubMsg);
- return $"{_alipayOptions.ServerUrl}?{response.Body}";
- }
-
- ///
- /// 交易预创建 🔖
- ///
- ///
- ///
- [DisplayName("交易预创建")]
- [ApiDescriptionSettings(Name = "AlipayPreCreate"), HttpPost]
- public string AlipayPreCreate(AlipayPreCreateInput input)
- {
- AlipayTradePrecreateRequest request = new();
-
- // 设置异步通知接收地址
- request.SetNotifyUrl(_alipayOptions.NotifyUrl);
-
- // 组装业务参数model
- AlipayTradePrecreateModel model = new()
- {
- Subject = input.Subject,
- OutTradeNo = input.OutTradeNo,
- TotalAmount = input.TotalAmount,
- TimeoutExpress = input.TimeoutExpress
- };
- request.SetBizModel(model);
-
- var response = _alipayClient.CertificateExecute(request);
- if (response.IsError) throw Oops.Oh(response.SubMsg);
- return response.QrCode;
- }
-
- ///
- /// 单笔转账到支付宝账户
- /// https://opendocs.alipay.com/open/62987723_alipay.fund.trans.uni.transfer
- ///
- [NonAction]
- public Task Transfer(AlipayFundTransUniTransferInput input)
- {
- // 构造请求参数以调用接口
- AlipayFundTransUniTransferRequest request = new();
- AlipayFundTransUniTransferModel model = new()
- {
- BizScene = AlipayConst.BizScene,
- ProductCode = AlipayConst.ProductCode,
-
- // 设置商家侧唯一订单号
- OutBizNo = input.OutBizNo,
-
- // 设置订单总金额
- TransAmount = input.TransAmount.ToString(),
-
- // 设置转账业务的标题
- OrderTitle = input.OrderTitle
- };
-
- // 设置收款方信息
- Participant payeeInfo = new()
- {
- CertType = input.CertType.ToString(),
- CertNo = input.CertNo,
- Identity = input.Identity,
- Name = input.Name,
- IdentityType = input.IdentityType.ToString()
- };
- model.PayeeInfo = payeeInfo;
-
- // 设置业务备注
- model.Remark = input.Remark;
-
- // 设置转账业务请求的扩展参数
- string payerShowNameUseAlias = input.PayerShowNameUseAlias.ToString().ToLower();
- model.BusinessParams = $"{{\"payer_show_name_use_alias\":\"{payerShowNameUseAlias}\"}}";
-
- request.SetBizModel(model);
- var response = _alipayClient.CertificateExecute(request);
-
- try
- {
- File.AppendAllText($"{_webHostEnvironment.ContentRootPath}\\AlipayLog\\{DateTime.Today:yyyy-MM-dd}.txt",
- $"支付宝付款到账户({DateTime.Now:yyyy-MM-dd HH:mm:ss}):{Environment.NewLine} " +
- $"登录人:{_userManager.UserId}-{_userManager.RealName}{Environment.NewLine} " +
- $"IP:{App.HttpContext?.GetRemoteIpAddressToIPv4(true)} {Environment.NewLine} " +
- $"参数:{JSON.Serialize(model)}{Environment.NewLine} " +
- $"返回:{JSON.Serialize(response)}{Environment.NewLine}" +
- $"-----------------------------------------------------------------------------------------------------------------------" +
- $"{Environment.NewLine}{Environment.NewLine}{Environment.NewLine}");
- }
- catch (Exception ex)
- {
- Log.Error("单笔转账到支付宝账户日志写入失败:", ex);
- }
- return Task.FromResult(response);
- }
-}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Service/Alipay/Dto/AlipayInput.cs b/Admin.NET/Admin.NET.Core/Service/Alipay/Dto/AlipayInput.cs
index 03421b25..178daad1 100644
--- a/Admin.NET/Admin.NET.Core/Service/Alipay/Dto/AlipayInput.cs
+++ b/Admin.NET/Admin.NET.Core/Service/Alipay/Dto/AlipayInput.cs
@@ -4,28 +4,37 @@
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+using System.Text.Json.Serialization;
using Aop.Api.Domain;
+using Newtonsoft.Json;
namespace Admin.NET.Core.Service;
public class AlipayFundTransUniTransferInput
{
///
- /// 商家侧唯一订单号
+ /// 用户ID
+ ///
+ public long UserId { get; set; }
+
+ ///
+ /// 商户AppId
+ ///
+ public string AppId { get; set; }
+
+ ///
+ /// 商家订单号
///
- [Required(ErrorMessage = "订单号不能为空")]
public string OutBizNo { get; set; }
///
/// 转账金额
///
- [Required(ErrorMessage = "转账金额不能为空")]
- public decimal? TransAmount { get; set; }
+ public decimal TransAmount { get; set; }
///
- /// 转账业务标题
+ /// 业务标题
///
- [Required(ErrorMessage = "业务标题不能为空")]
public string OrderTitle { get; set; }
///
@@ -46,25 +55,21 @@ public class AlipayFundTransUniTransferInput
///
/// 收款方证件号码,条件必填
///
- [CommonValidation($"{nameof(CertType)} != null && string.IsNullOrWhiteSpace({nameof(CertNo)})", "", ErrorMessage = "证件号码不能为空")]
public string CertNo { get; set; }
///
/// 收款方身份标识
///
- [Required(ErrorMessage = "身份标识不能为空")]
public string Identity { get; set; }
///
/// 收款方真实姓名
///
- [Required(ErrorMessage = "真实姓名不能为空")]
public string Name { get; set; }
///
/// 收款方身份标识类型
///
- [Required(ErrorMessage = "身份标识类型不能为空")]
public AlipayIdentityTypeEnum? IdentityType { get; set; }
}
@@ -159,10 +164,17 @@ public class AlipayAuthInfoInput
///
/// 用户Id
///
+
+ [JsonProperty("user_id")]
+ [JsonPropertyName("user_id")]
+ [FromQuery(Name = "user_id")]
public string UserId { get; set; }
///
/// 授权码
///
+ [JsonProperty("auth_code")]
+ [JsonPropertyName("auth_code")]
+ [FromQuery(Name = "auth_code")]
public string AuthCode { get; set; }
}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Core/Service/Alipay/SysAlipayService.cs b/Admin.NET/Admin.NET.Core/Service/Alipay/SysAlipayService.cs
new file mode 100644
index 00000000..e55af406
--- /dev/null
+++ b/Admin.NET/Admin.NET.Core/Service/Alipay/SysAlipayService.cs
@@ -0,0 +1,271 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+using Aop.Api;
+using Aop.Api.Domain;
+using Aop.Api.Request;
+using Aop.Api.Response;
+using Aop.Api.Util;
+using Microsoft.AspNetCore.Hosting;
+using NewLife.Reflection;
+
+namespace Admin.NET.Core.Service;
+
+///
+/// 支付宝支付服务 🧩
+///
+[ApiDescriptionSettings(Order = 240)]
+public class SysAlipayService : IDynamicApiController, ITransient
+{
+ private readonly IWebHostEnvironment _webHostEnvironment;
+ private readonly SysConfigService _sysConfigService;
+ private readonly List _alipayClientList;
+ private readonly IHttpContextAccessor _httpContext;
+ private readonly AlipayOptions _option;
+ private readonly ISqlSugarClient _db;
+
+ public SysAlipayService(
+ ISqlSugarClient db,
+ IHttpContextAccessor httpContext,
+ SysConfigService sysConfigService,
+ IWebHostEnvironment webHostEnvironment,
+ IOptions alipayOptions)
+ {
+ _db = db;
+ _httpContext = httpContext;
+ _sysConfigService = sysConfigService;
+ _option = alipayOptions.Value;
+ _webHostEnvironment = webHostEnvironment;
+
+ // 初始化支付宝客户端列表
+ _alipayClientList = [];
+ foreach (var account in _option.AccountList) _alipayClientList.Add(_option.GetClient(account));
+ }
+
+ ///
+ /// 获取授权信息 🔖
+ ///
+ ///
+ ///
+ [NonUnify]
+ [AllowAnonymous]
+ [DisplayName("获取授权信息")]
+ [ApiDescriptionSettings(Name = "AuthInfo"), HttpGet]
+ public ActionResult GetAuthInfo([FromQuery] AlipayAuthInfoInput input)
+ {
+ var type = input.UserId?.Split('-').FirstOrDefault().ToInt();
+ var userId = input.UserId?.Split('-').LastOrDefault().ToLong();
+ var account = _option.AccountList.FirstOrDefault();
+ var alipayClient = _alipayClientList.First();
+
+ // 当前网页接口地址
+ var currentUrl = $"{_option.AppAuthUrl}{_httpContext.HttpContext!.Request.Path}?userId={input.UserId}";
+ if (string.IsNullOrEmpty(input.AuthCode))
+ {
+ // 重新授权
+ var url = $"{_option.AuthUrl}?app_id={account!.AppId}&scope=auth_user&redirect_uri={currentUrl}";
+ return new RedirectResult(url);
+ }
+
+ // 组装授权请求参数
+ AlipaySystemOauthTokenRequest request = new()
+ {
+ GrantType = AlipayConst.GrantType,
+ Code = input.AuthCode
+ };
+ AlipaySystemOauthTokenResponse response = alipayClient.CertificateExecute(request);
+
+ // token换取用户信息
+ AlipayUserInfoShareRequest infoShareRequest = new();
+ AlipayUserInfoShareResponse info = alipayClient.CertificateExecute(infoShareRequest, response.AccessToken);
+
+ // 记录授权信息
+ var entity = _db.Queryable().First(u =>
+ (!string.IsNullOrWhiteSpace(u.UserId) && u.UserId == info.UserId) ||
+ (!string.IsNullOrWhiteSpace(u.OpenId) && u.OpenId == info.OpenId)) ?? new ();
+ entity.Copy(info, excludes: [nameof(SysAlipayAuthInfo.Gender), nameof(SysAlipayAuthInfo.Age)]);
+ entity.Age = int.Parse(info.Age);
+ entity.Gender = info.Gender switch
+ {
+ "m" => GenderEnum.Male,
+ "f" => GenderEnum.Female,
+ _ => GenderEnum.Unknown
+ };
+ entity.AppId = account!.AppId;
+ if (entity.Id <= 0) _db.Insertable(entity).ExecuteCommand();
+ else _db.Updateable(entity).ExecuteCommand();
+
+ // 执行完,重定向到指定界面
+ //var authPageUrl = _sysConfigService.GetConfigValueByCode(ConfigConst.AlipayAuthPageUrl + type).Result;
+ //return new RedirectResult(authPageUrl);
+ return new RedirectResult(_option.AppAuthUrl + "/index.html");
+ }
+
+ ///
+ /// 支付回调 🔖
+ ///
+ ///
+ [AllowAnonymous]
+ [DisplayName("支付回调")]
+ [ApiDescriptionSettings(Name = "Notify"), HttpPost]
+ public string Notify()
+ {
+ SortedDictionary sorted = [];
+ foreach (string key in _httpContext.HttpContext!.Request.Form.Keys)
+ sorted.Add(key, _httpContext.HttpContext.Request.Form[key]);
+
+ var account = _option.AccountList.FirstOrDefault();
+ string alipayPublicKey = Path.Combine(_webHostEnvironment.ContentRootPath, account!.AlipayPublicCertPath!.Replace('/', '\\').TrimStart('\\'));
+ bool signVerified = AlipaySignature.RSACertCheckV1(sorted, alipayPublicKey, "UTF-8", account.SignType); // 调用SDK验证签名
+ if (!signVerified) throw Oops.Oh("交易失败");
+
+ // 更新交易记录
+ var outTradeNo = sorted.GetValueOrDefault("out_trade_no");
+ var transaction = _db.Queryable().First(x => x.OutTradeNo == outTradeNo) ?? throw Oops.Oh("交易记录不存在");
+ transaction.TradeNo = sorted.GetValueOrDefault("trade_no");
+ transaction.TradeStatus = sorted.GetValueOrDefault("trade_status");
+ transaction.FinishTime = sorted.ContainsKey("gmt_payment") ? DateTime.Parse(sorted.GetValueOrDefault("gmt_payment")) : null;
+ transaction.BuyerLogonId = sorted.GetValueOrDefault("buyer_logon_id");
+ transaction.BuyerUserId = sorted.GetValueOrDefault("buyer_user_id");
+ transaction.SellerUserId = sorted.GetValueOrDefault("seller_id");
+ transaction.Remark = sorted.GetValueOrDefault("remark");
+ _db.Updateable(transaction).ExecuteCommand();
+
+ return "success";
+ }
+
+ ///
+ /// 统一收单下单并支付页面接口 🔖
+ ///
+ ///
+ ///
+ [DisplayName("统一收单下单并支付页面接口")]
+ [ApiDescriptionSettings(Name = "AlipayTradePagePay"), HttpPost]
+ public string AlipayTradePagePay(AlipayTradePagePayInput input)
+ {
+ // 创建交易记录,状态为等待支付
+ var transactionRecord = new SysAlipayTransaction
+ {
+ AppId = _option.AccountList.First().AppId,
+ OutTradeNo = input.OutTradeNo,
+ TotalAmount = input.TotalAmount.ToDecimal(),
+ TradeStatus = "WAIT_PAY", // 等待支付
+ CreateTime = DateTime.Now,
+ Subject = input.Subject,
+ Body = input.Body,
+ Remark = "等待用户支付"
+ };
+ _db.Insertable(transactionRecord).ExecuteCommand();
+
+ // 设置支付页面请求,并组装业务参数model,设置异步通知接收地址
+ AlipayTradeWapPayRequest request = new();
+ request.SetBizModel(new AlipayTradeWapPayModel()
+ {
+ Subject = input.Subject,
+ OutTradeNo = input.OutTradeNo,
+ TotalAmount = input.TotalAmount,
+ Body = input.Body,
+ ProductCode = "QUICK_WAP_WAY",
+ TimeExpire = input.TimeoutExpress
+ });
+ request.SetNotifyUrl(_option.NotifyUrl);
+
+ var alipayClient = _alipayClientList.First();
+ var response = alipayClient.SdkExecute(request);
+ if (response.IsError) throw Oops.Oh(response.SubMsg);
+ return $"{_option.ServerUrl}?{response.Body}";
+ }
+
+ ///
+ /// 交易预创建 🔖
+ ///
+ ///
+ ///
+ [DisplayName("交易预创建")]
+ [ApiDescriptionSettings(Name = "AlipayPreCreate"), HttpPost]
+ public string AlipayPreCreate(AlipayPreCreateInput input)
+ {
+ // 创建交易记录,状态为等待支付
+ var transactionRecord = new SysAlipayTransaction
+ {
+ AppId = _option.AccountList.First().AppId,
+ OutTradeNo = input.OutTradeNo,
+ TotalAmount = input.TotalAmount.ToDecimal(),
+ TradeStatus = "WAIT_PAY", // 等待支付
+ CreateTime = DateTime.Now,
+ Subject = input.Subject,
+ Remark = "等待用户支付"
+ };
+ _db.Insertable(transactionRecord).ExecuteCommand();
+
+ // 设置异步通知接收地址,并组装业务参数model
+ AlipayTradePrecreateRequest request = new();
+ request.SetNotifyUrl(_option.NotifyUrl);
+ request.SetBizModel(new AlipayTradePrecreateModel()
+ {
+ Subject = input.Subject,
+ OutTradeNo = input.OutTradeNo,
+ TotalAmount = input.TotalAmount,
+ TimeoutExpress = input.TimeoutExpress
+ });
+
+ var alipayClient = _alipayClientList.First();
+ var response = alipayClient.CertificateExecute(request);
+ if (response.IsError) throw Oops.Oh(response.SubMsg);
+ return response.QrCode;
+ }
+
+ ///
+ /// 单笔转账到支付宝账户
+ /// https://opendocs.alipay.com/open/62987723_alipay.fund.trans.uni.transfer
+ ///
+ [NonAction]
+ public async Task Transfer(AlipayFundTransUniTransferInput input)
+ {
+ var account = _option.AccountList.FirstOrDefault(u => u.AppId == input.AppId) ?? throw Oops.Oh("未找到商户支付宝账号");
+ var alipayClient = _option.GetClient(account);
+
+ // 构造请求参数以调用接口
+ AlipayFundTransUniTransferRequest request = new();
+ AlipayFundTransUniTransferModel model = new()
+ {
+ BizScene = AlipayConst.BizScene,
+ ProductCode = AlipayConst.ProductCode,
+ OutBizNo = input.OutBizNo, // 商家订单
+ TransAmount = $"{input.TransAmount}:F2", // 订单总金额
+ OrderTitle = input.OrderTitle, // 业务标题
+ Remark = input.Remark, // 业务备注
+ PayeeInfo = new() // 收款方信息
+ {
+ CertType = input.CertType?.ToString(),
+ CertNo = input.CertNo,
+ Identity = input.Identity,
+ Name = input.Name,
+ IdentityType = input.IdentityType.ToString()
+ },
+ BusinessParams = input.PayerShowNameUseAlias ? "{\"payer_show_name_use_alias\":\"true\"}" : null
+ };
+
+ request.SetBizModel(model);
+ var response = alipayClient.CertificateExecute(request);
+
+ // 保存转账记录
+ await _db.Insertable(new SysAlipayTransaction
+ {
+ UserId = input.UserId,
+ AppId = input.AppId,
+ TradeNo = response.OrderId,
+ OutTradeNo = input.OutBizNo,
+ TotalAmount = response.Amount.ToDecimal(),
+ TradeStatus = response.Code == "10000" ? "SUCCESS" : "FAILED",
+ Subject = input.OrderTitle,
+ ErrorInfo = response.SubMsg,
+ Remark = input.Remark
+ }).ExecuteCommandAsync();
+
+ return response;
+ }
+}
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Web.Entry/Alipaycrt/alipayPublicCert.crt b/Admin.NET/Admin.NET.Web.Entry/Alipaycrt/alipayPublicCert.crt
new file mode 100644
index 00000000..5ced5641
--- /dev/null
+++ b/Admin.NET/Admin.NET.Web.Entry/Alipaycrt/alipayPublicCert.crt
@@ -0,0 +1,38 @@
+-----BEGIN CERTIFICATE-----
+MIIDszCCApugAwIBAgIQICQSIl9wqwjbcsS1A/zPajANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UE
+BhMCQ04xGzAZBgNVBAoMEkFudCBGaW5hbmNpYWwgdGVzdDElMCMGA1UECwwcQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkgdGVzdDE+MDwGA1UEAww1QW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eSBDbGFzcyAyIFIxIHRlc3QwHhcNMjQxMjIyMTE0NzAzWhcNMjUxMjIyMTE0NzAzWjCB
+hDELMAkGA1UEBhMCQ04xHzAdBgNVBAoMFm10cXdudzEyODlAc2FuZGJveC5jb20xDzANBgNVBAsM
+BkFsaXBheTFDMEEGA1UEAww65pSv5LuY5a6dKOS4reWbvSnnvZHnu5zmioDmnK/mnInpmZDlhazl
+j7gtMjA4ODcyMTA1MzI1NzEzMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIPs9UeN
+0Hhp0qFTXE51E/a2EQ7YmMI8dJdBLWP17Irzo1I1Zxw3BIsrxEsdPJSGr76oQlunEyWYNyiVsOaL
+6KE8V1FK6uPSJr5BK5W9o3wKg3XX7BKdflyB4964uRNJOOPpqNi4vwY1ZZFVpSHrZJ0ZAthDHGYo
+o3/zdEEIwEWRkVAtMC6pJa8K0qk3qyaqHRMzwO3r13Ex8q/7+kO1iOsQ5UFQwKeV/g6/NuyEW9BZ
+6y59BehHQBqf51ZJcPa91Dc6va/C6McKe/OWd+km9EFwjab0L2GvwdRtrxUAikR0tghgvx3fAfJw
+nkfdjTzYUi/umDuVJlyW6xg0p9cJwLcCAwEAAaMSMBAwDgYDVR0PAQH/BAQDAgTwMA0GCSqGSIb3
+DQEBCwUAA4IBAQAoaQR/LYaBNMQ9pjEAHNaLdheebL6TbDNI8thKYAhMKFfeJ4ZNZPwqg2FnCfhf
+eVJctLqJtxgzzl0vazVGeFJRwrMvJXkZsU9veRjLP1s4QUOO5NqjxkDNuQnFnQZBsySLWkM/+0f3
+AcFImbXVUDuod/KnPZ6i2gbYNmaADAvYM8M87aqbvrfbLHBk6wtHR21l9MMu1BXyAlJn29k47xYj
+XNRJo6292M4Y4fyGFxT7tC+kt+MA6WUTl4hB+PvuXJh26tUOEo6EcXAZekcDJNOLCioNTW9/ck4P
+bj2Qxvouztndmd3zsT+flLiImEtGgRaClveKuUwrd9rzWLNkl2lw
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDszCCApugAwIBAgIQIBkIGbgVxq210KxLJ+YA/TANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UE
+BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxJTAjBgNVBAsMHENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5IHRlc3QxNjA0BgNVBAMMLUFudCBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgUjEgdGVzdDAeFw0xOTA4MTkxMTE2MDBaFw0yNDA4MDExMTE2MDBaMIGRMQswCQYDVQQGEwJD
+TjEbMBkGA1UECgwSQW50IEZpbmFuY2lhbCB0ZXN0MSUwIwYDVQQLDBxDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eSB0ZXN0MT4wPAYDVQQDDDVBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IENsYXNzIDIgUjEgdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMh4FKYO
+ZyRQHD6eFbPKZeSAnrfjfU7xmS9Yoozuu+iuqZlb6Z0SPLUqqTZAFZejOcmr07ln/pwZxluqplxC
+5+B48End4nclDMlT5HPrDr3W0frs6Xsa2ZNcyil/iKNB5MbGll8LRAxntsKvZZj6vUTMb705gYgm
+VUMILwi/ZxKTQqBtkT/kQQ5y6nOZsj7XI5rYdz6qqOROrpvS/d7iypdHOMIM9Iz9DlL1mrCykbBi
+t25y+gTeXmuisHUwqaRpwtCGK4BayCqxRGbNipe6W73EK9lBrrzNtTr9NaysesT/v+l25JHCL9tG
+wpNr1oWFzk4IHVOg0ORiQ6SUgxZUTYcCAwEAAaMSMBAwDgYDVR0PAQH/BAQDAgTwMA0GCSqGSIb3
+DQEBCwUAA4IBAQBWThEoIaQoBX2YeRY/I8gu6TYnFXtyuCljANnXnM38ft+ikhE5mMNgKmJYLHvT
+yWWWgwHoSAWEuml7EGbE/2AK2h3k0MdfiWLzdmpPCRG/RJHk6UB1pMHPilI+c0MVu16OPpKbg5Vf
+LTv7dsAB40AzKsvyYw88/Ezi1osTXo6QQwda7uefvudirtb8FcQM9R66cJxl3kt1FXbpYwheIm/p
+j1mq64swCoIYu4NrsUYtn6CV542DTQMI5QdXkn+PzUUly8F6kDp+KpMNd0avfWNL5+O++z+F5Szy
+1CPta1D7EQ/eYmMP+mOQ35oifWIoFCpN6qQVBS/Hob1J/UUyg7BW
+-----END CERTIFICATE-----
diff --git a/Admin.NET/Admin.NET.Web.Entry/Alipaycrt/alipayRootCert.crt b/Admin.NET/Admin.NET.Web.Entry/Alipaycrt/alipayRootCert.crt
new file mode 100644
index 00000000..d129c75e
--- /dev/null
+++ b/Admin.NET/Admin.NET.Web.Entry/Alipaycrt/alipayRootCert.crt
@@ -0,0 +1,88 @@
+-----BEGIN CERTIFICATE-----
+MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG
+EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw
+MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO
+UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE
+MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT
+V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti
+W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ
+MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b
+53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI
+pDoiVhsLwg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIF0zCCA7ugAwIBAgIIH8+hjWpIDREwDQYJKoZIhvcNAQELBQAwejELMAkGA1UE
+BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMyMTEzNDg0MFoXDTM4MDIyODEzNDg0
+MFowejELMAkGA1UEBhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNV
+BAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5j
+aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAtytTRcBNuur5h8xuxnlKJetT65cHGemGi8oD+beHFPTk
+rUTlFt9Xn7fAVGo6QSsPb9uGLpUFGEdGmbsQ2q9cV4P89qkH04VzIPwT7AywJdt2
+xAvMs+MgHFJzOYfL1QkdOOVO7NwKxH8IvlQgFabWomWk2Ei9WfUyxFjVO1LVh0Bp
+dRBeWLMkdudx0tl3+21t1apnReFNQ5nfX29xeSxIhesaMHDZFViO/DXDNW2BcTs6
+vSWKyJ4YIIIzStumD8K1xMsoaZBMDxg4itjWFaKRgNuPiIn4kjDY3kC66Sl/6yTl
+YUz8AybbEsICZzssdZh7jcNb1VRfk79lgAprm/Ktl+mgrU1gaMGP1OE25JCbqli1
+Pbw/BpPynyP9+XulE+2mxFwTYhKAwpDIDKuYsFUXuo8t261pCovI1CXFzAQM2w7H
+DtA2nOXSW6q0jGDJ5+WauH+K8ZSvA6x4sFo4u0KNCx0ROTBpLif6GTngqo3sj+98
+SZiMNLFMQoQkjkdN5Q5g9N6CFZPVZ6QpO0JcIc7S1le/g9z5iBKnifrKxy0TQjtG
+PsDwc8ubPnRm/F82RReCoyNyx63indpgFfhN7+KxUIQ9cOwwTvemmor0A+ZQamRe
+9LMuiEfEaWUDK+6O0Gl8lO571uI5onYdN1VIgOmwFbe+D8TcuzVjIZ/zvHrAGUcC
+AwEAAaNdMFswCwYDVR0PBAQDAgEGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFF90
+tATATwda6uWx2yKjh0GynOEBMB8GA1UdIwQYMBaAFF90tATATwda6uWx2yKjh0Gy
+nOEBMA0GCSqGSIb3DQEBCwUAA4ICAQCVYaOtqOLIpsrEikE5lb+UARNSFJg6tpkf
+tJ2U8QF/DejemEHx5IClQu6ajxjtu0Aie4/3UnIXop8nH/Q57l+Wyt9T7N2WPiNq
+JSlYKYbJpPF8LXbuKYG3BTFTdOVFIeRe2NUyYh/xs6bXGr4WKTXb3qBmzR02FSy3
+IODQw5Q6zpXj8prYqFHYsOvGCEc1CwJaSaYwRhTkFedJUxiyhyB5GQwoFfExCVHW
+05ZFCAVYFldCJvUzfzrWubN6wX0DD2dwultgmldOn/W/n8at52mpPNvIdbZb2F41
+T0YZeoWnCJrYXjq/32oc1cmifIHqySnyMnavi75DxPCdZsCOpSAT4j4lAQRGsfgI
+kkLPGQieMfNNkMCKh7qjwdXAVtdqhf0RVtFILH3OyEodlk1HYXqX5iE5wlaKzDop
+PKwf2Q3BErq1xChYGGVS+dEvyXc/2nIBlt7uLWKp4XFjqekKbaGaLJdjYP5b2s7N
+1dM0MXQ/f8XoXKBkJNzEiM3hfsU6DOREgMc1DIsFKxfuMwX3EkVQM1If8ghb6x5Y
+jXayv+NLbidOSzk4vl5QwngO/JYFMkoc6i9LNwEaEtR9PhnrdubxmrtM+RjfBm02
+77q3dSWFESFQ4QxYWew4pHE0DpWbWy/iMIKQ6UZ5RLvB8GEcgt8ON7BBJeMc+Dyi
+kT9qhqn+lw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICiDCCAgygAwIBAgIIQX76UsB/30owDAYIKoZIzj0EAwMFADB6MQswCQYDVQQG
+EwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UECwwXQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNpYWwgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgRTEwHhcNMTkwNDI4MTYyMDQ0WhcNNDkwNDIwMTYyMDQ0
+WjB6MQswCQYDVQQGEwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UE
+CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNp
+YWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRTEwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAASCCRa94QI0vR5Up9Yr9HEupz6hSoyjySYqo7v837KnmjveUIUNiuC9pWAU
+WP3jwLX3HkzeiNdeg22a0IZPoSUCpasufiLAnfXh6NInLiWBrjLJXDSGaY7vaokt
+rpZvAdmjXTBbMAsGA1UdDwQEAwIBBjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRZ
+4ZTgDpksHL2qcpkFkxD2zVd16TAfBgNVHSMEGDAWgBRZ4ZTgDpksHL2qcpkFkxD2
+zVd16TAMBggqhkjOPQQDAwUAA2gAMGUCMQD4IoqT2hTUn0jt7oXLdMJ8q4vLp6sg
+wHfPiOr9gxreb+e6Oidwd2LDnC4OUqCWiF8CMAzwKs4SnDJYcMLf2vpkbuVE4dTH
+Rglz+HGcTLWsFs4KxLsq7MuU+vJTBUeDJeDjdA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIUEMdk6dVgOEIS2cCP0Q43P90Ps5YwDQYJKoZIhvcNAQEF
+BQAwajELMAkGA1UEBhMCQ04xEzARBgNVBAoMCmlUcnVzQ2hpbmExHDAaBgNVBAsM
+E0NoaW5hIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMMH2lUcnVzQ2hpbmEgQ2xhc3Mg
+MiBSb290IENBIC0gRzMwHhcNMTMwNDE4MDkzNjU2WhcNMzMwNDE4MDkzNjU2WjBq
+MQswCQYDVQQGEwJDTjETMBEGA1UECgwKaVRydXNDaGluYTEcMBoGA1UECwwTQ2hp
+bmEgVHJ1c3QgTmV0d29yazEoMCYGA1UEAwwfaVRydXNDaGluYSBDbGFzcyAyIFJv
+b3QgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPPShpV
+nJbMqqCw6Bz1kehnoPst9pkr0V9idOwU2oyS47/HjJXk9Rd5a9xfwkPO88trUpz5
+4GmmwspDXjVFu9L0eFaRuH3KMha1Ak01citbF7cQLJlS7XI+tpkTGHEY5pt3EsQg
+wykfZl/A1jrnSkspMS997r2Gim54cwz+mTMgDRhZsKK/lbOeBPpWtcFizjXYCqhw
+WktvQfZBYi6o4sHCshnOswi4yV1p+LuFcQ2ciYdWvULh1eZhLxHbGXyznYHi0dGN
+z+I9H8aXxqAQfHVhbdHNzi77hCxFjOy+hHrGsyzjrd2swVQ2iUWP8BfEQqGLqM1g
+KgWKYfcTGdbPB1MCAwEAAaNjMGEwHQYDVR0OBBYEFG/oAMxTVe7y0+408CTAK8hA
+uTyRMB8GA1UdIwQYMBaAFG/oAMxTVe7y0+408CTAK8hAuTyRMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBLnUTfW7hp
+emMbuUGCk7RBswzOT83bDM6824EkUnf+X0iKS95SUNGeeSWK2o/3ALJo5hi7GZr3
+U8eLaWAcYizfO99UXMRBPw5PRR+gXGEronGUugLpxsjuynoLQu8GQAeysSXKbN1I
+UugDo9u8igJORYA+5ms0s5sCUySqbQ2R5z/GoceyI9LdxIVa1RjVX8pYOj8JFwtn
+DJN3ftSFvNMYwRuILKuqUYSHc2GPYiHVflDh5nDymCMOQFcFG3WsEuB+EYQPFgIU
+1DHmdZcz7Llx8UOZXX2JupWCYzK1XhJb+r4hK5ncf/w8qGtYlmyJpxk3hr1TfUJX
+Yf4Zr0fJsGuv
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/Admin.NET/Admin.NET.Web.Entry/Alipaycrt/appPublicCert.crt b/Admin.NET/Admin.NET.Web.Entry/Alipaycrt/appPublicCert.crt
new file mode 100644
index 00000000..a6a89dfa
--- /dev/null
+++ b/Admin.NET/Admin.NET.Web.Entry/Alipaycrt/appPublicCert.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDmTCCAoGgAwIBAgIQICQSIV6QZN2y3Knbwe6r9TANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UE
+BhMCQ04xGzAZBgNVBAoMEkFudCBGaW5hbmNpYWwgdGVzdDElMCMGA1UECwwcQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkgdGVzdDE+MDwGA1UEAww1QW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eSBDbGFzcyAyIFIxIHRlc3QwHhcNMjQxMjIxMTEzOTMzWhcNMjUxMjI2MTEzOTMzWjBr
+MQswCQYDVQQGEwJDTjEfMB0GA1UECgwWbXRxd253MTI4OUBzYW5kYm94LmNvbTEPMA0GA1UECwwG
+QWxpcGF5MSowKAYDVQQDDCEyMDg4NzIxMDUzMjU3MTMyLTkwMjEwMDAxNDI2ODYzOTUwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxJhoamnjWZGQp+1kHXTyQgA2va0rTQv8ZvFggERZv
+fOg2i5RYTBFLB0J1l3hj+23iBqzRTgzPxCLUTZUrj6WgwdDbXi11eE2wltVwmDHI1r3YdLC6KCQN
+Jpv6SKSHs9JV6UDpzsHaJbsoi6NymYpkbFClLCh3MOcyha9Ju4B9n5mKze1GEDTNcAs1nGfSsH1E
+wAWoe65iVM8pbTXTzjbEW/jJc2xbFT9RPRTihflkEf6p3kOpaPtgFmcUqdJ4BsldL6iWqbdR5JhT
+mVKT8hDmsbW9KpPnCXWedxBZHmNiuOOCOeDhHGV3zFrZvIPJa7umAL+eweg0egN5RHP9tDAnAgMB
+AAGjEjAQMA4GA1UdDwEB/wQEAwIE8DANBgkqhkiG9w0BAQsFAAOCAQEANPJelQG99aAZb+KXUE3Z
+ES+ZjPD9WwCBWpfcjyDq6duEQc9Qo0B2vW6EunbOi2qhS0dJ3pgJFaRrbi72BqQavT1eVYHcfXeC
+y8I3dI7oxn5BS944oiGTzaYTx6dJ8lXDmlQO8ULz+6/wBCkhr6TgKbjIOh7p3/B9NPcfL5z6OrbQ
+fXRk439uRfjWlzohE9q4cAY5AYnHLZCgbHwRX+YusDmJCu+LS9hioNHjwJ9t/jXsjzEQ09sfzEHF
+uPGKS4JGmzwqGp2Ly68MCzp7WOgEFBexYUio4suzKlZUcv1+HDi6fEosZ6Fr7Z3CEMwKelq8m2l7
+jg83G0PECp5unR1Hcw==
+-----END CERTIFICATE-----
\ No newline at end of file