refactor: 😀重构支付宝支付模块
This commit is contained in:
parent
e24e3befb5
commit
2df7100717
@ -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" // 支付宝公钥证书存放路径
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
149
Admin.NET/Admin.NET.Core/Entity/SysAlipayAuthInfo.cs
Normal file
149
Admin.NET/Admin.NET.Core/Entity/SysAlipayAuthInfo.cs
Normal file
@ -0,0 +1,149 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝授权记录表
|
||||
/// </summary>
|
||||
[SysTable]
|
||||
[SugarTable(null, "支付宝授权记录表")]
|
||||
[SugarIndex("index_{table}_U", nameof(UserId), OrderByType.Asc)]
|
||||
[SugarIndex("index_{table}_T", nameof(OpenId), OrderByType.Asc)]
|
||||
public class SysAlipayAuthInfo : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 商户AppId
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商户AppId", Length = 64)]
|
||||
public string? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开放ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "开放ID", Length = 64)]
|
||||
public string? OpenId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户ID", Length = 64)]
|
||||
public string? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "性别", Length = 8)]
|
||||
public GenderEnum Gender { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 年龄
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "年龄", Length = 16)]
|
||||
public int Age { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "手机号", Length = 32)]
|
||||
public string Mobile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 显示名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "显示名称", Length = 128)]
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 昵称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "昵称", Length = 64)]
|
||||
public string NickName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户名", Length = 64)]
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 头像
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "头像", Length = 512)]
|
||||
public string? Avatar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮箱
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "邮箱", Length = 128)]
|
||||
public string? Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户民族
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户民族", Length = 32)]
|
||||
public string? UserNation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 淘宝ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "淘宝ID", Length = 64)]
|
||||
public string? TaobaoId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 电话
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "电话", Length = 32)]
|
||||
public string? Phone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生日
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "生日", Length = 32)]
|
||||
public string? PersonBirthday { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 职业
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "职业", Length = 64)]
|
||||
public string? Profession { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 省份
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "省份", Length = 64)]
|
||||
public string? Province { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户状态", Length = 32)]
|
||||
public string? UserStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 学历
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "学历", Length = 32)]
|
||||
public string? Degree { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户类型
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户类型", Length = 32)]
|
||||
public string? UserType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮编
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "邮编", Length = 16)]
|
||||
public string? Zip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 地址
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "地址", Length = 256)]
|
||||
public string? Address { get; set; }
|
||||
}
|
||||
108
Admin.NET/Admin.NET.Core/Entity/SysAlipayTransaction.cs
Normal file
108
Admin.NET/Admin.NET.Core/Entity/SysAlipayTransaction.cs
Normal file
@ -0,0 +1,108 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝交易记录表
|
||||
/// </summary>
|
||||
[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
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户Id", Length = 64)]
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易号", Length = 64)]
|
||||
public string? TradeNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户订单号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商户订单号", Length = 64)]
|
||||
public string OutTradeNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易金额
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易金额", Length = 20)]
|
||||
public decimal TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易状态
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易状态", Length = 32)]
|
||||
public string TradeStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易完成时间
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易完成时间")]
|
||||
public DateTime? FinishTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易标题
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易标题", Length = 256)]
|
||||
public string Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易描述
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易描述", Length = 512)]
|
||||
public string? Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 买家支付宝账号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "买家支付宝账号", Length = 128)]
|
||||
public string? BuyerLogonId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 买家支付宝用户ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "买家支付宝用户ID", Length = 32)]
|
||||
public string? BuyerUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 卖家支付宝用户ID
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "卖家支付宝用户ID", Length = 32)]
|
||||
public string? SellerUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户AppId
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "商户AppId", Length = 64)]
|
||||
public string? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易扩展信息
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易扩展信息", Length = 1024)]
|
||||
public string? ExtendInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易异常信息
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易扩展信息", Length = 1024)]
|
||||
public string? ErrorInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易备注
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "交易备注", Length = 512)]
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
@ -4,6 +4,8 @@
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using Aop.Api;
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
@ -12,57 +14,106 @@ namespace Admin.NET.Core;
|
||||
public sealed class AlipayOptions : IConfigurableOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 支付宝 APPID(必填)
|
||||
/// 支付宝网关地址
|
||||
/// </summary>
|
||||
public string AppId { get; set; }
|
||||
public string ServerUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝 websocket 服务地址 (必填)
|
||||
/// 支付宝授权回调地址
|
||||
/// </summary>
|
||||
public string AlipayWebsocketUrl { get; set; }
|
||||
public string AuthUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝网关地址 (必填)
|
||||
/// 应用授权回调地址
|
||||
/// </summary>
|
||||
public string ServerUrl { get; set; }
|
||||
public string AppAuthUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝授权回调地址 (必填)
|
||||
/// 支付宝 websocket 服务地址
|
||||
/// </summary>
|
||||
public string AuthUrl { get; set; }
|
||||
public string WebsocketUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用回调地址
|
||||
/// </summary>
|
||||
public string NotifyUrl { get; set; }
|
||||
public string NotifyUrl { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 加密算法(必填)
|
||||
/// 支付宝根证书存放路径
|
||||
/// </summary>
|
||||
public string SignType { get; set; }
|
||||
public string RootCertPath { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝商户账号列表
|
||||
/// </summary>
|
||||
public List<AlipayMerchantAccount> AccountList { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取支付宝客户端
|
||||
/// </summary>
|
||||
/// <param name="account"></param>
|
||||
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)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝商户账号信息
|
||||
/// </summary>
|
||||
public class AlipayMerchantAccount
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置Id
|
||||
/// </summary>
|
||||
public long Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户名称
|
||||
/// </summary>
|
||||
public string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户AppId
|
||||
/// </summary>
|
||||
public string AppId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用私钥
|
||||
/// </summary>
|
||||
public string PrivateKey { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 从支付宝获取敏感信息时的加密密钥(可选)
|
||||
/// </summary>
|
||||
public string EncryptKey { get; set; }
|
||||
public string EncryptKey { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用私钥 (必填)
|
||||
/// 加密算法
|
||||
/// </summary>
|
||||
public string PrivateKey { get; set; }
|
||||
public string SignType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝公钥证书存放路径(证书加签方式必填)
|
||||
/// 应用公钥证书路径
|
||||
/// </summary>
|
||||
public string AlipayPublicCertPath { get; set; }
|
||||
public string AppCertPath { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝根证书存放路径(证书加签方式必填)
|
||||
/// 支付宝公钥证书路径
|
||||
/// </summary>
|
||||
public string RootCertPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用公钥证书存放路径(证书加签方式必填)
|
||||
/// </summary>
|
||||
public string AppCertPath { get; set; }
|
||||
public string AlipayPublicCertPath { get; init; }
|
||||
}
|
||||
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝支付服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 240)]
|
||||
public class AlipayService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly IEnumerable<IAlipayNotify> _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> alipayOptions)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_httpContext = httpContext;
|
||||
_sysConfigService = sysConfigService;
|
||||
_alipayOptions = alipayOptions.Value;
|
||||
_webHostEnvironment = webHostEnvironment;
|
||||
_alipayNotifyList = App.GetServices<IAlipayNotify>();
|
||||
|
||||
// 初始化支付宝客户端
|
||||
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)
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取授权信息 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[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<string>(ConfigConst.AlipayAuthPageUrl + type).Result;
|
||||
return new RedirectResult(authPageUrl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 支付回调 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("支付回调")]
|
||||
[ApiDescriptionSettings(Name = "Notify"), HttpPost]
|
||||
public string Notify()
|
||||
{
|
||||
SortedDictionary<string, string> 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";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一收单下单并支付页面接口 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[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}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 交易预创建 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单笔转账到支付宝账户
|
||||
/// https://opendocs.alipay.com/open/62987723_alipay.fund.trans.uni.transfer
|
||||
/// </summary>
|
||||
[NonAction]
|
||||
public Task<AlipayFundTransUniTransferResponse> 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);
|
||||
}
|
||||
}
|
||||
@ -4,28 +4,37 @@
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using Aop.Api.Domain;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
public class AlipayFundTransUniTransferInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 商家侧唯一订单号
|
||||
/// 用户ID
|
||||
/// </summary>
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商户AppId
|
||||
/// </summary>
|
||||
public string AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商家订单号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "订单号不能为空")]
|
||||
public string OutBizNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 转账金额
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "转账金额不能为空")]
|
||||
public decimal? TransAmount { get; set; }
|
||||
public decimal TransAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 转账业务标题
|
||||
/// 业务标题
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "业务标题不能为空")]
|
||||
public string OrderTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -46,25 +55,21 @@ public class AlipayFundTransUniTransferInput
|
||||
/// <summary>
|
||||
/// 收款方证件号码,条件必填
|
||||
/// </summary>
|
||||
[CommonValidation($"{nameof(CertType)} != null && string.IsNullOrWhiteSpace({nameof(CertNo)})", "", ErrorMessage = "证件号码不能为空")]
|
||||
public string CertNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收款方身份标识
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "身份标识不能为空")]
|
||||
public string Identity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收款方真实姓名
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "真实姓名不能为空")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收款方身份标识类型
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "身份标识类型不能为空")]
|
||||
public AlipayIdentityTypeEnum? IdentityType { get; set; }
|
||||
}
|
||||
|
||||
@ -159,10 +164,17 @@ public class AlipayAuthInfoInput
|
||||
/// <summary>
|
||||
/// 用户Id
|
||||
/// </summary>
|
||||
|
||||
[JsonProperty("user_id")]
|
||||
[JsonPropertyName("user_id")]
|
||||
[FromQuery(Name = "user_id")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 授权码
|
||||
/// </summary>
|
||||
[JsonProperty("auth_code")]
|
||||
[JsonPropertyName("auth_code")]
|
||||
[FromQuery(Name = "auth_code")]
|
||||
public string AuthCode { get; set; }
|
||||
}
|
||||
271
Admin.NET/Admin.NET.Core/Service/Alipay/SysAlipayService.cs
Normal file
271
Admin.NET/Admin.NET.Core/Service/Alipay/SysAlipayService.cs
Normal file
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝支付服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Order = 240)]
|
||||
public class SysAlipayService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly IWebHostEnvironment _webHostEnvironment;
|
||||
private readonly SysConfigService _sysConfigService;
|
||||
private readonly List<IAopClient> _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> alipayOptions)
|
||||
{
|
||||
_db = db;
|
||||
_httpContext = httpContext;
|
||||
_sysConfigService = sysConfigService;
|
||||
_option = alipayOptions.Value;
|
||||
_webHostEnvironment = webHostEnvironment;
|
||||
|
||||
// 初始化支付宝客户端列表
|
||||
_alipayClientList = [];
|
||||
foreach (var account in _option.AccountList) _alipayClientList.Add(_option.GetClient(account));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取授权信息 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[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<SysAlipayAuthInfo>().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<string>(ConfigConst.AlipayAuthPageUrl + type).Result;
|
||||
//return new RedirectResult(authPageUrl);
|
||||
return new RedirectResult(_option.AppAuthUrl + "/index.html");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 支付回调 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[DisplayName("支付回调")]
|
||||
[ApiDescriptionSettings(Name = "Notify"), HttpPost]
|
||||
public string Notify()
|
||||
{
|
||||
SortedDictionary<string, string> 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<SysAlipayTransaction>().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";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一收单下单并支付页面接口 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[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}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 交易预创建 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单笔转账到支付宝账户
|
||||
/// https://opendocs.alipay.com/open/62987723_alipay.fund.trans.uni.transfer
|
||||
/// </summary>
|
||||
[NonAction]
|
||||
public async Task<AlipayFundTransUniTransferResponse> 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;
|
||||
}
|
||||
}
|
||||
38
Admin.NET/Admin.NET.Web.Entry/Alipaycrt/alipayPublicCert.crt
Normal file
38
Admin.NET/Admin.NET.Web.Entry/Alipaycrt/alipayPublicCert.crt
Normal file
@ -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-----
|
||||
88
Admin.NET/Admin.NET.Web.Entry/Alipaycrt/alipayRootCert.crt
Normal file
88
Admin.NET/Admin.NET.Web.Entry/Alipaycrt/alipayRootCert.crt
Normal file
@ -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-----
|
||||
19
Admin.NET/Admin.NET.Web.Entry/Alipaycrt/appPublicCert.crt
Normal file
19
Admin.NET/Admin.NET.Web.Entry/Alipaycrt/appPublicCert.crt
Normal file
@ -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-----
|
||||
Loading…
Reference in New Issue
Block a user