.NetCore支付宝支付-服务商模式(saas)

准备工作

介绍

支付宝服务商模式,可以替商户完成收款功能,商户无需自己研发即可完成收款功能。基于saas企业开发可以采用此种模式替商户完成支付流程

引入如下Nuget包依赖

<PackageReference Include="AlipaySDKNet.Standard" Version="4.6.0" />
<PackageReference Include="Essensoft.AspNetCore.Payment.Alipay" Version="2.4.6" />

支付宝子商户配置

 "AlipayPartnerPayConfig": { // 支付宝服务商配置
   "appId": "20**************",  //服务商AppId
   "alipayPublicKey": "********************",//支付宝公钥
   "appPrivateKey": "***************************",//应用私钥
   "payExpireTime": "35" //支付过期时间(单位:分)
 },

代码实现
支付宝支付入口

 #region
 _logger.LogInformation($"开始发起支付宝支付");
 //支付宝支付
 var alipayPayRequest = new AlipayH5PayCreateRequest {
     MemberCode = memberCode,
     OutTradeNo = orderInfo.OutOrderId, // 第三方订单号
     Subject = orderInfo.ProductName,
     TotalAmount = orderInfo.OrderAmount?.ToString("#0.00"),
     NotifyUrl = $"{_apiUrlConfigOption.NotifyUrl}/api/Cashier/alipayPayCallback",
     ReturnUrl = request.ReturnUrl ?? orderInfo.ReturnUrl, // request.ReturnUrl,
     QuitUrl = request.QuitUrl
 };
 _logger.LogInformation($"支付宝支付,调服务层基础服务接口,入参:{alipayPayRequest.ToJson()}");
 var rsAlipay = await _partnerPaymentService.AlipayH5PayCreate(alipayPayRequest);

 _logger.LogInformation($"支付宝支付,调服务层基础服务接口,结果:{rsAlipay?.ToJson()}");
 if (rsAlipay == null || rsAlipay.Code != "0") {
     return (false, rsAlipay?.Message ?? "支付宝支付失败");
 }
 return (true, rsAlipay.Data);
 #endregion

PartnerPaymentService.cs服务商支付核心代码

    /// <summary>
    /// 服务商模式支付
    /// </summary>
    public class PartnerPaymentService : IPartnerPaymentService
    {
        /// <summary>
        /// 实体映射
        /// </summary>
        protected IMapper _mapper;

        private readonly ILogger _logger;
        private readonly ITracer _tracer;

        private readonly IHttpContextAccessor _httpContextAccessor;

        private readonly IAliPaymentService _aliPaymentService;
        private readonly IOptions<AlipayOptions> _optionsAccessor;
        private readonly IOptions<WechatPayPartnerPayConfigOption> _wechatPayPartnerPayConfig;
        private readonly IOptions<AlipayPartnerPayConfigOption> _AlipayPartnerPayConfig;
        private readonly IProxyHttpClient _proxyHttpClient;
        private readonly AppSettings _appSettings;
        private readonly ApiUrlConfigOption _apiUrlConfigOption;

        /// <summary>
        /// 初始化一个<see cref="PartnerPaymentService"/>类型的实例
        /// </summary>
        /// <param name="mapper">实体映射</param>
        /// <param name="logger"></param>
        /// <param name="tracer"></param>
        /// <param name="aliPaymentService"></param>
        /// <param name="optionsAccessor"></param>
        /// <param name="apiEndpoints"></param>
        /// <param name="httpContextAccessor"></param>
        public PartnerPaymentService(IMapper mapper, ILogger<PartnerPaymentService> logger, 
        ITracer tracer, 
        IHttpContextAccessor httpContextAccessor,
            IOptions<WechatPayPartnerPayConfigOption> wechatPayPartnerPayConfig,
            IOptions<AlipayPartnerPayConfigOption> alipayPartnerPayConfig, 
            IAliPaymentService aliPaymentService,
            IOptions<AlipayOptions> optionsAccessor,
            IOptions<ApiUrlConfigOption> apiUrlConfigOption,
             IProxyHttpClient proxyHttpClient,
             AppSettings appSettings) {
            _mapper = mapper;
            _logger = logger;
            _tracer = tracer;
            _httpContextAccessor = httpContextAccessor;
            _wechatPayPartnerPayConfig = wechatPayPartnerPayConfig;
            _AlipayPartnerPayConfig = alipayPartnerPayConfig;
            _aliPaymentService = aliPaymentService;
            _optionsAccessor = optionsAccessor;
            _proxyHttpClient = proxyHttpClient;
            _appSettings = appSettings;
            _apiUrlConfigOption = apiUrlConfigOption.Value;
        }

        #region 支付宝
        /// <summary>
        /// 支付宝支付
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<DataResponse<string>> AlipayH5PayCreate(AlipayH5PayCreateRequest request) {
            _logger.LogInformation($"支付宝支付,入参:{request.ToJson()}");

            //获得支付配置
            var (options, alipayConfig) = await GetAlipayPayOptions(request.MemberCode);
            //切换动态配置
            _aliPaymentService.OptionsAccessor = new OptionsWrapper<AlipayOptions>(options);

            var param = new AlipayWapPayModel {
                OutTradeNo = request.OutTradeNo,
                Subject = request.Subject,
                SellerId = alipayConfig.PId,
                TotalAmount = request.TotalAmount,
                NotifyUrl = request.NotifyUrl,
                ReturnUrl = request.ReturnUrl,
                AppAuthToken = alipayConfig.AppAuthToken,
                PayExpireTime = alipayConfig.PayExpireTime,
                QuitUrl = request.QuitUrl
            };
            var (result, response) = await _aliPaymentService.WapPay(param);
            _logger.LogInformation($"支付宝支付,结果:{response?.ToJson()}_{result}");

            if (string.IsNullOrWhiteSpace(result) || response == null || response.IsError) {
                return ResponseResult.Execute(string.Empty, "-1", $"{response?.Code}{response?.SubMsg ?? "支付宝错误"}");
            }

            return ResponseResult.Execute(result);
        }

        /// <summary>
        /// 支付宝支付查询
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<DataResponse<PayQueryResponse>> AlipayPayQuery(AlipayPayQueryRequest request) {
            _logger.LogInformation($"支付宝支付查询,入参:{request.ToJson()}");

            //获得支付配置
            var (options, aplipayConfig) = await GetAlipayPayOptions(request.MemberCode);
            //切换动态配置
            _aliPaymentService.OptionsAccessor = new OptionsWrapper<AlipayOptions>(options);

            var param = new AlipayQueryModel {
                OutTradeNo = request.OutTradeNo,
                AppAuthToken = aplipayConfig.AppAuthToken
            };
            var response = await _aliPaymentService.Query(param);
            _logger.LogInformation($"支付宝支付查询,结果:{response?.ToJson()}");

            if (response == null || response.IsError) {
                return ResponseResult.Execute(new PayQueryResponse(), "-1", $"{response?.Code}{response?.SubMsg ?? "支付宝错误"}");
            }

            return ResponseResult.Execute(new PayQueryResponse {
                TradeState = response.TradeStatus,
                PayNumber = response.TradeNo
            });
        }

        /// <summary>
        /// 支付宝支付退款
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<DataResponse<bool>> AlipayPayRefund(AlipayPayRefundRequest request) {
            _logger.LogInformation($"支付宝支付退款,入参:{request.ToJson()}");
            //获得支付配置
            var (options, aplipayConfig) = await GetAlipayPayOptions(request.MemberCode);
            //切换动态配置
            _aliPaymentService.OptionsAccessor = new OptionsWrapper<AlipayOptions>(options);

            var param = new AlipayRefundModel {
                OutTradeNo = request.OutTradeNo,
                RefundAmount = request.RefundAmount,
                AppAuthToken = aplipayConfig.AppAuthToken,
                OutRequestNo = request.OutRequestNo

            };
            var (result, response) = await _aliPaymentService.Refund(param);
            _logger.LogInformation($"支付宝支付退款,结果:{response?.ToJson()}_{result}");

            if (response == null || response.IsError) {
                return ResponseResult.Execute(false, "-1", $"{response?.Code}{response?.SubMsg ?? "支付宝错误"}");
            }

            return ResponseResult.Execute(result);
        }
        #endregion

        /// <summary>
        /// 支付宝服务商支付options
        /// </summary>
        /// <param name="tenantId"></param>
        /// <returns></returns>
        private async Task<(AlipayOptions, AlipayPayPartnerPayConfigModel)> GetAlipayPayOptions(string tenantId = null) {
            var payConfig = await GetAlipayPayConfig("AlipayPartnerPay", tenantId);

            var options = new AlipayOptions {
                AppId = payConfig.AppId,
                AlipayPublicKey = payConfig.AlipayPublicKey,
                AppPrivateKey = payConfig.AppPrivateKey
            };

            return (options, payConfig);
        }
        /// <summary>
        /// 获取支付宝支付配置
        /// </summary>
        /// <param name="parameterCode"></param>
        /// <param name="memberCode"></param>
        /// <returns></returns>
        public async Task<AlipayPayPartnerPayConfigModel> GetAlipayPayConfig(string parameterCode, string memberCode = null) {
            var payConfig = new AlipayPayPartnerPayConfigModel {
                AppId = _AlipayPartnerPayConfig.Value.AppId,
                AlipayPublicKey = _AlipayPartnerPayConfig.Value.AlipayPublicKey,
                AppPrivateKey = _AlipayPartnerPayConfig.Value.AppPrivateKey,
                PayExpireTime = _AlipayPartnerPayConfig.Value.PayExpireTime,
            };

            if (!string.IsNullOrWhiteSpace(memberCode)) {
                payConfig.PId = "******";
                payConfig.AppAuthToken = "******";
            }

            return payConfig;
        }
    }

AliPaymentService.cs 支付宝底层支付核心方法

using System;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Aop.Api;
using Essensoft.AspNetCore.Payment.Alipay;
using ICH.Util.Extension;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Payment.Alipay.Model;

namespace Payment.Alipay
{
    public class AliPaymentService : IAliPaymentService
    {
        private readonly IAlipayClient _client;
        public IOptions<AlipayOptions> OptionsAccessor { get; set; }
        private readonly ILogger _logger;

        public AliPaymentService(IOptions<AlipayOptions> optionsAccessor, IAlipayClient client, ILogger<AliPaymentService> logger)
        {
            OptionsAccessor = optionsAccessor;
            _client = client;
            _logger = logger;
        }
        public async Task<(string, Aop.Api.Response.AlipayTradeWapPayResponse)> WapPay(AlipayWapPayModel model)
        {
            _logger.LogInformation($"支付宝wap支付入参:{model.ToJson()}");
            var payModel = new Aop.Api.Domain.AlipayTradeWapPayModel
            {
                Body = model.Body,
                Subject = model.Subject,
                TotalAmount = model.TotalAmount,
                OutTradeNo = model.OutTradeNo,
                SellerId = model.SellerId,
                PassbackParams = HttpUtility.UrlEncode(model.PassbackParams),
                ProductCode = model.ProductCode,
                TimeExpire = DateTime.Now.AddMinutes(model.PayExpireTime).ToString("yyyy-MM-dd HH:mm"),
                QuitUrl = model.QuitUrl
            };

            var request = new Aop.Api.Request.AlipayTradeWapPayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数
//此次只是参数展示,未进行字符串转义,实际情况下请转义
            request.SetBizModel(payModel);
            request.SetNotifyUrl(model.NotifyUrl);
            request.SetReturnUrl(model.ReturnUrl);
            _logger.LogInformation($"支付宝支付:{model.ToJson()}");
            
            
            DefaultAopClient client = new Aop.Api.DefaultAopClient("https://openapi.alipay.com/gateway.do",
                OptionsAccessor.Value.AppId, OptionsAccessor.Value.AppPrivateKey, "json", "1.0", "RSA2",
                OptionsAccessor.Value.AlipayPublicKey, "utf-8", false);

            var response = client.pageExecute(request, null, model.AppAuthToken,"POST");
             
//调用成功,则处理业务逻辑
            if(!response.IsError)
            {
                var body = response?.Body;
                
                return (GetWapPayUrlToHtml(body), response);
            }
            
            return (string.Empty, new Aop.Api.Response.AlipayTradeWapPayResponse());

        }

        public async Task<(bool, Aop.Api.Response.AlipayTradeRefundResponse)> Refund(AlipayRefundModel model)
        {
            _logger.LogInformation($"支付宝退款入参:{model.ToJson()}");

            var refundModel = new Aop.Api.Domain.AlipayTradeRefundModel()
            {
                OutTradeNo = model.OutTradeNo,
                TradeNo = model.TradeNo,
                RefundAmount = model.RefundAmount,
                OutRequestNo = model.OutRequestNo,
                RefundReason = model.RefundReason
            };
            var request = new Aop.Api.Request.AlipayTradeRefundRequest();
            request.SetBizModel(refundModel);
            _logger.LogInformation($"支付宝退款:{refundModel.ToJson()}");
            
            DefaultAopClient client = new Aop.Api.DefaultAopClient("https://openapi.alipay.com/gateway.do",
                OptionsAccessor.Value.AppId, OptionsAccessor.Value.AppPrivateKey, "json", "1.0", "RSA2",
                OptionsAccessor.Value.AlipayPublicKey, "utf-8", false);
            var response = client.Execute(request, null, model.AppAuthToken,"POST");
             
            _logger.LogInformation($"aliRefundResponse:{response?.ToJson()}");
            return (response?.IsError == false && response.Code ==
                     "10000" && response.Msg == "Success" && response.FundChange == "Y", response);
        }

        /// <summary>
        /// 查询
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<Aop.Api.Response.AlipayTradeQueryResponse> Query(AlipayQueryModel model)
        {
            var queryModel = new Aop.Api.Domain.AlipayTradeQueryModel
            {
                OutTradeNo = model.OutTradeNo,
                TradeNo = model.TradeNo
            };
            var request = new Aop.Api.Request.AlipayTradeQueryRequest();
            request.SetBizModel(queryModel);

            _logger.LogInformation($"支付宝查询:{queryModel.ToJson()}");

            DefaultAopClient client = new Aop.Api.DefaultAopClient("https://openapi.alipay.com/gateway.do",
                OptionsAccessor.Value.AppId, OptionsAccessor.Value.AppPrivateKey, "json", "1.0", "RSA2",
                OptionsAccessor.Value.AlipayPublicKey, "utf-8", false);
            var response = client.Execute(request, null, model.AppAuthToken,"POST");

            _logger.LogInformation($"wechatAlipayResponse:{response?.ToJson()}");
           
            return response;
        }

        /// <summary>
        ///     通过form获取url
        /// </summary>
        /// <param name="payForm"></param>
        /// <returns></returns>
        private static string GetWapPayUrlToHtml(string payForm)
        {
            HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
            document.LoadHtml(payForm);

            try
            {
                var rootnode = document.DocumentNode;
                var form = rootnode.SelectSingleNode("form");
                var urlSb = new StringBuilder();
                var url = form.Attributes["action"].Value;
                url = url.Split('?')[0];
                urlSb.Append(url);
                var appid = form.SelectSingleNode("input[@name=\"app_id\"]").Attributes["value"].Value;
                urlSb.Append("?app_id=" + appid);

                var bizContent = form.SelectSingleNode("input[@name=\"biz_content\"]").Attributes["value"].Value;
                urlSb.Append("&biz_content=" + System.Web.HttpUtility.UrlEncode(bizContent));

                var charset = form.SelectSingleNode("input[@name=\"charset\"]").Attributes["value"].Value;
                urlSb.Append("&charset=" + charset);

                var format = form.SelectSingleNode("input[@name=\"format\"]").Attributes["value"].Value;
                urlSb.Append("&format=" + format);

                var method = form.SelectSingleNode("input[@name=\"method\"]").Attributes["value"].Value;
                urlSb.Append("&method=" + System.Web.HttpUtility.UrlEncode(method));

                var notifyUrl = form.SelectSingleNode("input[@name=\"notify_url\"]").Attributes["value"].Value;
                urlSb.Append("&notify_url=" + System.Web.HttpUtility.UrlEncode(notifyUrl));

                var returnUrl = form.SelectSingleNode("input[@name=\"return_url\"]").Attributes["value"].Value;
                urlSb.Append("&return_url=" + System.Web.HttpUtility.UrlEncode(returnUrl));

                var signType = form.SelectSingleNode("input[@name=\"sign_type\"]").Attributes["value"].Value;
                urlSb.Append("&sign_type=" + signType);

                var timestamp = form.SelectSingleNode("input[@name=\"timestamp\"]").Attributes["value"].Value;
                urlSb.Append("&timestamp=" + System.Web.HttpUtility.UrlEncode(timestamp));

                var version = form.SelectSingleNode("input[@name=\"version\"]").Attributes["value"].Value;
                urlSb.Append("&version=" + version);

                var sign = form.SelectSingleNode("input[@name=\"sign\"]").Attributes["value"].Value;
                urlSb.Append("&sign=" + System.Web.HttpUtility.UrlEncode(sign));
                
                var alipaySdk = form.SelectSingleNode("input[@name=\"alipay_sdk\"]")?.Attributes["value"]?.Value;
                if (!string.IsNullOrWhiteSpace(alipaySdk))
                {
                    urlSb.Append("&alipay_sdk=" + System.Web.HttpUtility.UrlEncode(alipaySdk));
                }

                var appAuthToken = form.SelectSingleNode("input[@name=\"app_auth_token\"]")?.Attributes["value"]?.Value;
                if (!string.IsNullOrWhiteSpace(appAuthToken))
                {
                    urlSb.Append("&app_auth_token=" + System.Web.HttpUtility.UrlEncode(appAuthToken));
                }

                return urlSb.ToString();
            }
            catch
            {
                return "";
            }
        }
    }
}

总结

  1. 子商户需要签约服务商模式特约商户才可以支付
  2. 签约为子商户后会得到{“pid”:““, “appAuthToken”:””}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值