.net core 支付宝,微信支付 一

源码: https://github.com/aspros-luo/Qwerty.Payment/tree/develop

 支付宝支付:参考支付宝sdk及文档,https://docs.open.alipay.com/194

前言:

目前实现支付宝Native支付,手机网站支付,App支付,支付回调,退款申请,退款查询

Native支付及手机支付是由前端加基础数据传入后端,后端加签拼装成html以二维码或form表单呈现

APP支付由后端加签,返回加签结果给app,app直接调用sdk完成支付

1:设置支付需要的config信息,考虑到会有不同appId,所以需要设置appId,私钥和公钥

public static class AliPayConfig
    {
        public static void Init(string appId, string privateKey, string aliPublicKey, string returnUrl, string notifyUrl)
        {
            AppId = appId;
            PrivateKey = privateKey;
            AliPublicKey = aliPublicKey;
            ReturnUrl = string.IsNullOrWhiteSpace(returnUrl) ? notifyUrl : returnUrl;
            NotifyUrl = notifyUrl;
        }

        public static string AppId { get; private set; }
        //public static string Gateway { get; private set; } = "https://openapi.alipay.com/gateway.do";
        internal static string Gateway { get; private set; } = "https://openapi.alipaydev.com/gateway.do";
        public static string PrivateKey { get; private set; }
        public static string AliPublicKey { get; private set; }
        public static string ReturnUrl { get; private set; }
        public static string NotifyUrl { get; private set; }
    }
View Code

2:通用方法,组装数据,排序,加签,验签等

2.1:拼装数据类

主要用于字典排序拼装

public static string BuildParamStr(Dictionary<string, string> param)
        {
            if (param == null || param.Count == 0)
            {
                return "";
            }
            var ascDic = param.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value);
            var sb = new StringBuilder();
            foreach (var item in ascDic)
            {
                if (!string.IsNullOrEmpty(item.Value))
                {
                    sb.Append(item.Key).Append("=").Append(item.Value).Append("&");
                }
            }
            return sb.ToString().Substring(0, sb.ToString().Length - 1);
        }
View Code

主要用于扫码,jsapi手机网站支付拼装成一个form表单,(支付宝sdk中也有)

public static string BuildHtmlRequest(IDictionary<string, string> sParaTemp, string strMethod, string strButtonValue)
        {
            //待请求参数数组
            var dicPara = sParaTemp;
            var sbHtml = new StringBuilder();
            //sbHtml.Append("<head><meta http-equiv=\"Content-Type\" content=\"text/html\" charset= \"" + charset + "\" /></head>");
            sbHtml.Append("<form id='alipaysubmit' name='alipaysubmit' action='"+AliPayConfig.Gateway+"?charset=utf-8' method='" + strMethod + "'>");
            foreach (var temp in dicPara)
            {
                sbHtml.Append("<input  name='" + temp.Key + "' value='" + temp.Value + "'/>");
            }
            //submit按钮控件请不要含有name属性
            sbHtml.Append("<input type='submit' value='" + strButtonValue + "' style='display:none;'></form>");
            // sbHtml.Append("<input type='submit' value='" + strButtonValue + "'></form></div>");
            //表单实现自动提交
            sbHtml.Append("<script>document.forms['alipaysubmit'].submit();</script>");
            return sbHtml.ToString();
        }
View Code

2.2:签名类,RSA256签名,支付宝推荐rsa256签名方式,私钥是java格式,这里引用一个nuget包,转换成dotnet格式私钥

Org.BouncyCastle

/// <summary>
    /// Rsa 工具类
    /// </summary>
    internal static class GenerateRsaAssist
    {
        /// <summary>
        /// 加签
        /// </summary>
        /// <returns></returns>
        public static string RasSign(string content, string privateKey, SignType signType)
        {
            var singerType = "";
            if (signType == SignType.Rsa2)
            {
                singerType = "SHA256WithRSA";
            }
            if (signType == SignType.Rsa)
            {
                singerType = "SHA1withRSA";
            }
            var signer = SignerUtilities.GetSigner(singerType);
            var privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
            signer.Init(true, privateKeyParam);
            var plainBytes = Encoding.UTF8.GetBytes(content);
            signer.BlockUpdate(plainBytes, 0, plainBytes.Length);
            var signBytes = signer.GenerateSignature();
            return Convert.ToBase64String(signBytes);
        }
        /// <summary>
        /// 验签
        /// </summary>
        /// <returns></returns>
        public static bool VerifySign(string content, string publicKey, string signData, SignType signType)
        {
            var singerType = "";
            if (signType == SignType.Rsa2)
            {
                singerType = "SHA256WithRSA";
            }
            if (signType == SignType.Rsa)
            {
                singerType = "SHA1withRSA";
            }
            var signer = SignerUtilities.GetSigner(singerType);
            var publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
            signer.Init(false, publicKeyParam);
            var signBytes = Convert.FromBase64String(signData);
            var plainBytes = Encoding.UTF8.GetBytes(content);
            signer.BlockUpdate(plainBytes, 0, plainBytes.Length);
            var ret = signer.VerifySignature(signBytes);
            return ret;
        }
    }
View Code

3:基础类

通用方法基本完成后剩下的只要基础类来组装数据了

3.1:添加公共请求参数类

internal class AliPayCommonModel
    {
        public string app_id { get; private set; } = AliPayConfig.AppId;
        public string method { get; private set; }
        public string format { get; private set; } = "JSON";
        public string return_url { get; private set; } = AliPayConfig.ReturnUrl;
        public string charset { get; private set; } = "utf-8";
        public string sign_type { get; private set; } = "RSA2";
        public string timestamp { get; private set; } = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss}";
        public string version { get; private set; } = "1.0";
        public string notify_url { get;private set; }= AliPayConfig.NotifyUrl;
        public string biz_content { get; private set; }
        /// <summary>
        /// 设置支付方式
        /// </summary>
        /// <param name="payMethod"></param>
        internal void SetMethod(string payMethod)
        {
            method = payMethod;
        }
        /// <summary>
        /// 设置支付主题内容
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pay"></param>
        internal void SetBizContent<T>(T pay)
        {
            var str = pay.GetType().GetProperties().OrderBy(o=>o.Name).Aggregate("", (current, item) => current + $"\"{item.Name}\":\"{item.GetValue(pay)}\",");
            biz_content ="{"+ str.Substring(0,str.Length-1)+"}";
        }

        //public void SetBizContent(AliRefundModel refund)
        //{
        //    var str = refund.GetType().GetProperties().OrderBy(o => o.Name).Aggregate("", (current, item) => current + $"\"{item.Name}\":\"{item.GetValue(refund)}\",");
        //    biz_content = "{" + str.Substring(0, str.Length - 1) + "}";
        //}

        //public void SetBizContent(AliRefundQueryModel refundQuery)
        //{
        //    var str = refundQuery.GetType().GetProperties().OrderBy(o => o.Name).Aggregate("", (current, item) => current + $"\"{item.Name}\":\"{item.GetValue(refundQuery)}\",");
        //    biz_content = "{" + str.Substring(0, str.Length - 1) + "}";
        //}

    }
View Code

公共参数类里包含两个方法,设置不同支付方式及设置支付主体

3.2:添加支付主体类

    public class AliPayModel
    {
        /// <summary>
        /// 商户交易订单号
        /// </summary>
        public string out_trade_no { get; set; }
        /// <summary>
        /// 支付类型
        /// </summary>
        public string product_code { get; private set; } = "FAST_INSTANT_TRADE_PAY";
        /// <summary>
        /// 支付金额
        /// </summary>
        public string total_amount { get; set; }
        /// <summary>
        /// 标题
        /// </summary>
        public string subject { get; set; }
        /// <summary>
        /// 有效时间
        /// </summary>
        public string timeout_express { get; set; } = "30m";
        /// <summary>
        /// 设置支付方式
        /// </summary>
        /// <param name="code"></param>
        internal void SetProductCode(string code)
        {
            product_code = code;
        }
    }
View Code

支付主体里也有一个方法设置销售产品码,用于设置商家和支付宝签约的产品码

4:添加网络请求类,没什么特别的,将键值数据传入支付宝请求网关,主要用于退款申请,及退款查询,native支付及手机网站支付都只是在后端加签sign后拼装成html输出的

    internal class HttpUtil
    {
        //private static readonly string _defaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";

        //private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        //{
        //    return true; //总是接受     
        //}

        internal static async Task<HttpResponseMessage> CreatePostHttpResponse(string url, IDictionary<string, string> parameters)
        {
            var listKeyValues = parameters.Keys.Select(key => new KeyValuePair<string, string>(key, parameters[key])).ToList();
            using (var client = new HttpClient())
            {
                var httpContent = new FormUrlEncodedContent(listKeyValues);
                var response = await client.PostAsync(url, httpContent);
                return response;
            }
        }
    }
View Code

5:接口,及实现类

定义支付方式接口,目前涵盖native,手机网站,app支付,退款申请,退款查询,当面付功能暂未实现

public interface IAliPayService
    {
        /// <summary>
        /// page支付,支付信息组成页面表单数据,用于pc支付
        /// </summary>
        /// <returns></returns>
        AliPayRequest NativePay(AliPayModel payModel);
        /// <summary>
        /// app支付,app端发送加签字段,返回签名数据
        /// </summary>
        /// <returns></returns>
        AliPayRequest AppPay(string preSign);
        /// <summary>
        /// jsapi支付,用于网页支付
        /// </summary>
        /// <returns></returns>
        AliPayRequest JsApiPay(AliPayModel payModel);
        /// <summary>
        /// 退款申请接口,用户发起退款申请
        /// </summary>
        /// <returns></returns>
        Task<AliRefundResponse> AliRefund(AliRefundModel refundModel);
        /// <summary>
        /// 退款查询接口,用于确认退款是否成功
        /// </summary>
        /// <returns></returns>
        Task<AliRefundQueryResponse> AliRefundQuery(AliRefundQueryModel refundQueryModel);
        /// <summary>
        /// 支付回掉接口
        /// </summary>
        /// <returns></returns>
        AliNotifyRequest AliNotify(Stream aliReturnData);
    }
View Code

实现接口类(敲黑板,画重点)

   public class AliPayService : IAliPayService
    {
        public AliPayRequest NativePay(AliPayModel payModel)
        {
            payModel.SetProductCode("FAST_INSTANT_TRADE_PAY");

            var common = new AliPayCommonModel();
            common.SetMethod("alipay.trade.page.pay");
            common.SetBizContent(payModel);

            var parameters = common.GetType().GetProperties().OrderBy(o => o.Name).ToDictionary(item => item.Name, item => item.GetValue(common).ToString());
            var str = BuildData.BuildParamStr(parameters);

            var sign = GenerateRsaAssist.RasSign(str, AliPayConfig.PrivateKey, SignType.Rsa2);
            parameters.Add("sign", sign);

            try
            {
                var from = BuildData.BuildHtmlRequest(parameters, "post", "post");
                return new AliPayRequest { IsSuccess = true, PreSign = str, Sign = sign, Result = from };
            }
            catch (Exception e)
            {
                return new AliPayRequest { IsSuccess = false, PreSign = str, Sign = sign, Result = e.Message };
            }
        }

        public AliPayRequest AppPay(string preSign)
        {
            try
            {
                //payModel.SetProductCode("QUICK_MSECURITY_PAY");
                //var common = new AliPayCommonModel();
                //common.SetMethod("alipay.trade.app.pay");
                //common.SetBizContent(payModel);
                //var parameters = common.GetType().GetProperties().OrderBy(o => o.Name).ToDictionary(item => item.Name, item => item.GetValue(common).ToString());
                //var str = BuildData.BuildParamStr(parameters);
                var sign = GenerateRsaAssist.RasSign(preSign, AliPayConfig.PrivateKey, SignType.Rsa2);
                //return UrlEncoder.Default.Encode(str)+$"&sign={sign}";
                sign = UrlEncoder.Default.Encode(sign);
                return new AliPayRequest { IsSuccess = true, PreSign = preSign, Sign = sign, Result = sign };
            }
            catch (Exception e)
            {
                return new AliPayRequest { IsSuccess = false, PreSign = preSign, Sign = "", Result = e.Message };
            }

        }

        public AliPayRequest JsApiPay(AliPayModel payModel)
        {
            payModel.SetProductCode("QUICK_WAP_WAY");

            var common = new AliPayCommonModel();
            common.SetMethod("alipay.trade.wap.pay");
            common.SetBizContent(payModel);

            var parameters = common.GetType().GetProperties().OrderBy(o => o.Name).ToDictionary(item => item.Name, item => item.GetValue(common).ToString());
            var str = BuildData.BuildParamStr(parameters);

            var sign = GenerateRsaAssist.RasSign(str, AliPayConfig.PrivateKey, SignType.Rsa2);
            parameters.Add("sign", sign);

            try
            {
                var from = BuildData.BuildHtmlRequest(parameters, "post", "post");
                return new AliPayRequest { IsSuccess = true, PreSign = str, Sign = sign, Result = from };
            }
            catch (Exception e)
            {
                return new AliPayRequest { IsSuccess = false, PreSign = str, Sign = sign, Result = e.Message };
            }
        }

        public async Task<AliRefundResponse> AliRefund(AliRefundModel refundModel)
        {
            var common = new AliPayCommonModel();
            common.SetMethod("alipay.trade.refund");
            common.SetBizContent(refundModel);

            var parameters = common.GetType().GetProperties().OrderBy(o => o.Name).ToDictionary(item => item.Name, item => item.GetValue(common).ToString());
            var str = BuildData.BuildParamStr(parameters);

            var sign = GenerateRsaAssist.RasSign(str, AliPayConfig.PrivateKey, SignType.Rsa2);
            parameters.Add("sign", sign);

            var response = await HttpUtil.CreatePostHttpResponse(AliPayConfig.Gateway, parameters);
            var result = await response.Content.ReadAsStringAsync();

            var jsonResult = JsonConvert.DeserializeObject<AliRefundResponse>(result);
            return jsonResult;
        }

        public async Task<AliRefundQueryResponse> AliRefundQuery(AliRefundQueryModel refundQueryModel)
        {
            var common = new AliPayCommonModel();
            common.SetMethod("alipay.trade.fastpay.refund.query");
            common.SetBizContent(refundQueryModel);
            var parameters = common.GetType().GetProperties().OrderBy(o => o.Name).ToDictionary(item => item.Name, item => item.GetValue(common).ToString());
            var str = BuildData.BuildParamStr(parameters);
            var sign = GenerateRsaAssist.RasSign(str, AliPayConfig.PrivateKey, SignType.Rsa2);
            parameters.Add("sign", sign);
            var response = await HttpUtil.CreatePostHttpResponse(AliPayConfig.Gateway, parameters);
            var result = await response.Content.ReadAsStringAsync();
            var jsonResult = JsonConvert.DeserializeObject<AliRefundQueryResponse>(result);
            return jsonResult;
        }

        public AliNotifyRequest AliNotify(Stream aliReturnData)
        {
            try
            {
                //获取回调参数
                var s = aliReturnData;
                int count;
                var buffer = new byte[1024];
                var builder = new StringBuilder();
                while ((count = s.Read(buffer, 0, 1024)) > 0)
                {
                    builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
                }
                s.Flush();
                s.Dispose();
                //request 接收的字符串含有urlencode,这里需要decode一下
                var alipayReturnData = builder.ToString().Split('&').ToDictionary(a => a.Split('=')[0], a => System.Net.WebUtility.UrlDecode(a.Split('=')[1]));
                //获取sign
                var sign = alipayReturnData["sign"];
                //去除sign及signtype
                alipayReturnData.Remove("sign");
                alipayReturnData.Remove("sign_type");
                //获取支付宝订单号及商户交易订单号
                var tradeNo = alipayReturnData["trade_no"];
                var tradeIds = alipayReturnData["out_trade_no"];

                var dic = alipayReturnData.ToDictionary(d => d.Key, d => d.Value);

                var preSign = BuildData.BuildParamStr(dic);
                //验签
                var result = GenerateRsaAssist.VerifySign(preSign, AliPayConfig.AliPublicKey, sign, SignType.Rsa2);

                return result
                    ?
                    new AliNotifyRequest { IsVerify = true, PayNo = tradeNo, TradeIds = tradeIds, PayTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Sign = sign, Content = preSign }
                    :
                    new AliNotifyRequest { IsVerify = false, PayNo = tradeNo, TradeIds = "", PayTime = "", Sign = sign, Content = preSign };
            }
            catch (Exception e)
            {
                return new AliNotifyRequest { IsVerify = false, PayNo = "", TradeIds = "", PayTime = "", Sign = "", Content = e.Message };
            }
        }
    }
View Code

a.接口参数主体为支付主体类,方法实现前,主体设置销售产品码

native支付:FAST_INSTANT_TRADE_PAY

手机网站支付:QUICK_WAP_WAY(旧版手机网站支付未涵盖)

b.设置公共参数,设置接口名

native支付接口名:alipay.trade.page.pay

手机网站支付接口名:alipay.trade.wap.pay

c.app支付比较特殊,需要Ios或Android将数据拼接完成后传入后端加签返回给app,再由app支付sdk调起

需要注意的一个问题是, var sign = GenerateRsaAssist.RasSign(preSign, AliPayConfig.PrivateKey, SignType.Rsa2);

加签得到的sign需要urlencode一下再返回,不然app调起会出错

 sign = UrlEncoder.Default.Encode(sign);

 

退款神器,及退款查询也需要添加主体类,这里就不再赘述

下一篇应该补上微信支付

支付宝支付如果有遗漏内容,请告知

如果发现任何问题也烦请指正。

long may the sunshine ~!

转载于:https://www.cnblogs.com/AsprosL/p/7661480.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
微信支付是一种非常常见的支付方式,可以用于线上和线下的交易。在.NET Core 3.1中,我们可以使用微信支付的扫码付款功能来实现支付功能。 首先,我们需要在微信支付商户平台上注册一个商户账号,并获得相应的API密钥和商户ID。 接着,在.NET Core 3.1应用程序中,我们可以使用第三方开源库,如第三方SDK,如“Senparc.Weixin”来实现与微信支付的交互。 在代码中,我们首先要引入相应的命名空间和依赖项。然后,我们可以创建一个支付请求对象,包括必要的参数,如订单号、金额、商品信息等。 接下来,我们可以使用微信支付提供的API,生成一个支付二维码,并将其展示给用户。用户可以使用微信扫描这个二维码来完成支付。 在用户完成支付后,微信支付会向我们提供一个支付结果通知。我们可以在.NET Core 3.1应用程序中编写一个接收支付结果通知的接口,并对接收到的通知进行验证和处理。根据支付结果,我们可以更新订单状态,完成支付流程。 另外,为了保证支付的安全性,我们还需要进行签名和加密操作,以确保支付请求和结果在传输过程中不被篡改。在.NET Core 3.1中,我们可以使用相应的加密算法和方法来对数据进行加密和解密。 总结来说,通过在.NET Core 3.1应用程序中使用微信支付的扫码付款功能,我们可以实现一个简单的支付功能,同时保证支付的安全性和可靠性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值