【移动支付】.NET支付宝App支付接入

一、前言

       最近也是为了新产品忙得起飞,博客都更新的慢了。新产品为了方便用户支付,需要支付宝扫码接入。这活落到了我的身上。产品是Windows系统下的桌面软件,通过软件生成二维码支付。界面以原生的MVVM编写,下面叙述一下基本的过程,做过的老司机可以直接点关闭了。

二、申请接口

        申请接口是第一步,首先有这么几件事:

  1. 公司具有支付宝账户
  2. 公司具有营业资质(废话)
  3. 创建应用,签约电脑网站支付,手机支付,App支付。
  4. 创建私钥、公钥、支付宝公钥
  5. 配置网关及回调地址

需要注意的是以下几点:

  1. 创建应用时,名称不要带有“支付”、“pay”等字样,图片建议高清
  2. 创建应用时,签约支付需要一些申请材料,如:营业资质照片,公司照片4张,应用的介绍(名称,下载地址,公司网站是否有该应用,该应用出现支付宝支付的界面样式)
  3. 签约后需要审核,大致一天,(阿里确实快,腾讯微信要4天),审核通过会发送一份邮件,里面有链接,点击链接完成签约
  4. 创建私钥、公钥、支付宝公钥,在支付宝接口网站上有官方工具,下载使用即可
  5. 网关与回调地址要与公司网站形成关联,比如是二级域名;如果网关、回调地址与公司网站没什么联系,恐怕不行。

三、代码流程

        有三个构成元素。客户端软件,商户服务器后台,支付宝后台

客户端软件点击“获取支付二维码”去获得一个可支付的二维码:

封装客户端的一些必要信息发送给商户服务器后台形成一个商户订单

        /// <summary>
        /// 获取二维码信息
        /// </summary>
        /// <param name="packageClientInfo">封装信息</param>
        /// <param name="serverAddress">商户产品服务器地址</param>
        /// <returns></returns>
        public static void GetQRCodeInfo(string packageClientInfo, string serverAddress, Action<string> getQRCodeAction)
        {
            if (!string.IsNullOrEmpty(packageClientInfo))
            {
                try
                {
                    HttpClient httpsClient = new HttpClient
                    {
                        BaseAddress = new Uri(serverAddress),
                        Timeout = TimeSpan.FromMinutes(20)
                    };

                    if (DsClientOperation.ConnectionTest(httpsClient))
                    {
                        StringContent strData = new StringContent(
                                                           packageClientInfo,
                                                           Encoding.UTF8,
                                                           RcCommonNames.JasonMediaType);
                        string PostUrl = httpsClient.BaseAddress + "api/AlipayForProduct/GetQRCodeString";
                        Uri address = new Uri(PostUrl);
                        Task<HttpResponseMessage> response = httpsClient.PostAsync(address, strData);
                        response.ContinueWith(
                            (postTask) =>
                            {
                                if (postTask.IsFaulted)
                                {
                                    throw postTask.Exception;
                                }
                                HttpResponseMessage postResponse = postTask.Result;
                                postResponse.EnsureSuccessStatusCode();
                                var result = postResponse.Content.ReadAsStringAsync().Result;
                                getQRCodeAction(JsonConvert.DeserializeObject<string>(result)); //注意这个委托
                                return result;
                            });
                    }
                }
                catch
                {
                    // ignored
                }
            }
        }

这里的委托方法是用来生成二维码的,当你从这个“api/AlipayForProduct/GetQRCodeString”返回一些字符串(result),比如返回的是:

"http://xxx.xxx.com/AlipayForProduct/SendInfoToAlipay?ordernumber=" + $"{orderNumber}";(orderNumber为商户订单号)

然后使用ThoughtWorks.QRCode.dll去生成二维码

        /// <summary>
        /// 根据字符串得到相应的二维码
        /// </summary>
        /// <param name="qrInfo"></param>
        /// <param name="productName"></param>
        /// <param name="version"></param>
        /// <returns></returns>
        public static Image CreateQRCodeImage(string qrInfo, string productName, string version)
        {
            try
            {
                if (!string.IsNullOrEmpty(qrInfo))
                {
                    QRCodeEncoder encoder = new QRCodeEncoder
                    {
                        QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE,
                        QRCodeScale = 4,
                        QRCodeVersion = 0,
                        QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.M
                    };
                    //编码方式(注意:BYTE能支持中文,ALPHA_NUMERIC扫描出来的都是数字)
                    //大小(值越大生成的二维码图片像素越高)
                    //版本(注意:设置为0主要是防止编码的字符串太长时发生错误)
                    //错误效验、错误更正(有4个等级)

                    Image image = encoder.Encode(qrInfo, Encoding.GetEncoding("utf-8"));
                    string filename = $"{productName}_{version}.png";
                    var userLocalPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
                    var docPath = Path.Combine(userLocalPath, @"YourProduct\QRCode");
                    if (!Directory.Exists(docPath))
                    {
                        Directory.CreateDirectory(docPath);
                    }
                    string filepath = Path.Combine(docPath, filename);
                    using (FileStream fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write))
                    {
                        image.Save(fs, System.Drawing.Imaging.ImageFormat.Png);
                        fs.Close();
                        image.Dispose();
                    }
                    return image;
                }
            }
            catch (Exception)
            {
                return null;
            }
            return null;
        }

这样就产生了二维码,说白了,就是把一个服务的api由字符串变成了图片,当用户使用支付宝app去扫这个二维码时,会去请求这个api:

"http://xxx.xxx.com/AlipayForProduct/SendInfoToAlipay?ordernumber=" + $"{orderNumber}";(orderNumber为商户订单号)

        public string SendInfoToAlipay()
        {
            string orderNumber = Request["orderNumber"];
            if (!string.IsNullOrEmpty(orderNumber))
            {
                var matchedItem = db.OrderInfoForProduct.FirstOrDefault(x => x.OrderNumber == orderNumber); //验证下商户服务器后台有没有这个订单
                if (matchedItem != null && matchedItem.IsPaid == false)
                {
                    //公共参数
                    var alipayServerURL = "https://openapi.alipay.com/gateway.do";
                    var app_id = appID;
                    var privateKeyPem = applicationPrivateKey;
                    var format = "json";
                    var version = "1.0";
                    var signType = "RSA2";

                    //请求参数
                    var out_trade_no = orderNumber; //商家订单号
                    var product_code = "FAST_INSTANT_TRADE_PAY"; //销售产品码
                    var total_amount = "Your Money";  //订单总金额
                    var subject = "Your Title"; //订单标题
                    var body = "Your Body"; //订单描述

                    IAopClient client = new DefaultAopClient(
                        alipayServerURL,
                        app_id,
                        privateKeyPem,
                        format,
                        version,
                        signType);

                    var returnurl = $"http://xxx.xxx.com/AlipayForProduct/AlipayResult";
                    var notifyurl = $"http://xxx.xxx.com/AlipayForProduct/UpdatePayStatus";
                    AlipayTradeWapPayRequest requestWap = new AlipayTradeWapPayRequest
                    {
                        BizContent = "{" +
                                     "    \"body\":\"" + body + "\"," +
                                     "    \"subject\":\"" + subject + "\"," +
                                     "    \"out_trade_no\":\"" + out_trade_no + "\"," +
                                     "    \"total_amount\":" + total_amount + "," +
                                     "    \"product_code\":\"" + product_code + "\"" +
                                     "  }"
                    };

                    requestWap.SetNotifyUrl(notifyurl); //异步请求
                    requestWap.SetReturnUrl(returnurl); //同步请求

                    AlipayTradeWapPayResponse responseWap = client.pageExecute(requestWap);

                    string divNone = "<div style=‘display:none‘>" + responseWap.Body + "</div>";
                    return divNone;
                }
            }
            return string.Empty;
        }

异步请求一般需要做这么几件事:

  1. 用户扫码支付完之后,支付宝后台会把所有需要验证的信息发给你,除了一个参数不需要验签完,其余都需要验签;
  2. 如果验签成功且支付状态也是成功交易后,你需要更新商户服务器后台关于此条商户订单的状态,比如将其支付状态变成已支付,填充支付时间等等;
        /// <summary>
        /// 回调函数
        /// </summary>
        [HttpPost]
        public void UpdatePayStatus()
        {
            SortedDictionary<string, string> sPara = GetRequestPost();

            if (sPara.Count > 0)
            {
                //非验签参数
                var sign_type = Request.Form["sign_type"];

                //接收参数并排序
                var seller_id = Request.Form["seller_id"]; //卖家支付宝用户号
                var trade_status = Request.Form["trade_status"]; //交易状态
                var notify_time = Request.Form["notify_time"]; //通知时间
                var app_id = Request.Form["app_id"]; //开发者AppId
                var out_trade_no = Request.Form["out_trade_no"]; //交易订单号
                var total_amount = Request.Form["total_amount"]; //订单金额
                var receipt_amount = Request.Form["receipt_amount"]; //实收金额
                var invoice_amount = Request.Form["invoice_amount"]; //开票金额
                var buyer_pay_amount = Request.Form["buyer_pay_amount"]; //付款金额
                var body = Request.Form["body"]; //商品描述
                var gmt_payment = Request.Form["gmt_payment"]; //交易付款时间

                var tradeGuid = new Guid(out_trade_no);
                //验签
                try
                {
                    var isVerfied = AlipaySignature.RSACheckV1(sPara, alipayPublicKey, "utf-8", sign_type, false);
                    if (isVerfied)
                    {
                        if (app_id == appID && seller_id == sellerID)
                        {                          var isTradeSuccess = string.Equals(trade_status, "TRADE_SUCCESS") || string.Equals(trade_status, "TRADE_FINISHED");
                            if (isTradeSuccess)
                            {
                                //商户验证逻辑及数据更新逻辑
                            }
                        }
                    }
                }
                catch (Exception)
                {

                }
            }
            else
            {

            }
        }

/// <summary>        /// 参数排序字典        /// </summary>        /// <returns></returns>        private SortedDictionary<string, string> GetRequestPost()        {            SortedDictionary<string, string> sArray = new SortedDictionary<string, string>();            NameValueCollection coll = Request.Form;            String[] requestItem = coll.AllKeys;            foreach (string t in requestItem)            {                sArray.Add(t, Request.Form[t]);            }            return sArray;        }

同步请求一般需要做这么几件事:

1. 当异步调用完后,如果支付成功而且商户服务器后台对此条订单号处理也正确的话;同步请求可以再做一次验证

2. 如果验证成功,跳转支付成功页面;如果失败,跳转支付失败页面。

        public ActionResult AlipayResult()
        {
            SortedDictionary<string, string> sPara = GetRequestGet();
            if (sPara.Count > 0)
            {
                //非验签参数
                var sign_type = Request.QueryString["sign_type"];

                //接收参数并排序
                var seller_id = Request.QueryString["seller_id"]; //卖家支付宝用户号
                var app_id = Request.QueryString["app_id"]; //开发者AppId
                var out_trade_no = Request.QueryString["out_trade_no"]; //交易订单号

                var orderNumberGuid = new Guid(out_trade_no);
                try
                {
                    var isVerfied = AlipaySignature.RSACheckV1(sPara, alipayPublicKey, "utf-8", sign_type, false);
                    if (isVerfied)
                    {
                        if (app_id == appID && seller_id == sellerID)
                        {
                           //你的支付成功页面
                        }
                    }

                }
                catch
                {
                   //你的支付失败页面
                }
            }
            else
            {
               //你的支付失败页面
            }
            return View();
        }

        /// <summary>
        /// 参数排序字典
        /// </summary>
        /// <returns></returns>
        private SortedDictionary<string, string> GetRequestGet()
        {
            SortedDictionary<string, string> sArray = new SortedDictionary<string, string>();
            NameValueCollection coll = Request.QueryString;

            String[] requestItem = coll.AllKeys;

            foreach (string t in requestItem)
            {
                sArray.Add(t, Request.QueryString[t]);
            }
            return sArray;
        }

四、结尾

       参加工作以来一直主攻WPF,偶尔搞搞Web还是挺有趣的!

时间: 2024-10-14 06:24:52

【移动支付】.NET支付宝App支付接入的相关文章

支付宝APP支付开发- IOException : DerInputStream.getLength(): lengthTag=127, too big.

支付宝APP支付Java开发报错: 1 IOException : DerInputStream.getLength(): lengthTag=127, too big. 后来排查是因为没有设置私钥.

支付宝APP支付开发- IOException : DER input, Integer tag error

支付宝APP支付Java开发报错: 1 java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DER input, Integer tag error 后来发现,原来是支付宝,生成的命令有问题,参数放错位置 将(3) 的命令改为: openssl pkcs8 -topk8 -nocrypt -inform PEM -in rsa_private_key.pem -o

支付宝app支付java后台流程及原理分析

java版支付宝app支付流程及原理分析 本实例是基于springmvc框架编写     一.流程步骤         1.执行流程           当手机端app(就是你公司开发的app)在支付页面时,调起服务端(后台第1个创建订单接口)接口,后台把需要调起支付宝支付的参数返回给手机端,手机端拿到         这些参数后,拉起支付宝支付环境完成支付,完成支付后会调异步通知(第2个接口),此时需要给支付宝返回成功或者失败信息,成功后会调用同步通知(第3个接口)         返回支付成

支付宝APP支付里设置应用网关和授权回调地址是不必填的

支付宝APP支付里设置应用网关和授权回调地址位置为: 支付宝app支付应用网关和授权回调地址为非必填,详细解释链接:https://openclub.alipay.com/read.php?tid=1339&fid=2

.Net后台实现支付宝APP支付

前面讨论了微信支付,接下来聊聊支付宝的APP支付(新款支付宝支付).其实这些支付原理都一样,只不过具体到每个支付平台,所使用的支付配置参数不同,返回至支付端的下单参数也不同. 话不多说,直接上代码. 在App.Pay项目中使用NuGet管理器添加引用Alipay.AopSdk,也可以不添加引用,将官方SDK源码放至项目中. 添加完引用后,我们就可以开工了,新建文件夹AliPay,在文件夹中新建AliPayConfig类,存放支付宝APP支付所需的参数,同样,这些参数我也放在了配置文件中. 1 u

关于支付宝app支付服务端的实现-Java版

前言 最近在工作中需要使用支付宝app支付,在初次使用过程中也不可避免的出现了一些问题,那么本次随笔主要是概述支付宝app支付服务端的整个实现过程以及就服务端出现的一些问题做一些总结. 1.准备工作 1.1 入驻蚂蚁金服开放平台 https://open.alipay.com/platform/home.htm 1.2 创建应用 首先需要创建一个应用. 然后需要设置应用公钥. 下载支付宝密钥生成器.生成成功之后将公钥复制到这里. 最后提交审核,等待. 2.Maven依赖 首先需要下载SDK,ht

支付宝 app支付 沙盘使用

文档说明 沙箱测试: App支付沙箱接入注意点 1.app支付支持沙箱接入:在沙箱调通接口后,必须在线上进行测试与验收,所有返回码及业务逻辑以线上为准:2.app支付只支持余额支付,不支持银行卡.余额宝等其他支付方式:3.app支付只支持Android版接入,在使用sdk时,在支付接口前调用如下方法 EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX); 用于切换沙箱环境与生产环境:如果不使用此方法,默认使用生产环境:在钱包不存在的情况下,会唤起h5支付: 注:在生

H5集成支付宝App支付客户端+服务端(java)

由于最近项目需要接入第三方开发,支付宝支付,微信支付,OSS图片上传以及短信服务.为避免第一次开发支付宝再次花时间查看文档,今天总结一下接入支付宝的过程,以及接入过程中遇到的问题. 1.首先在蚂蚁金服开放平台申请应用https://open.alipay.com/platform/home.htm,App支付需要签约后才能生效,签约只需提供完成资料即可通过审核. 2.在已申请应用中查看签约状态,若状态为已生效才可以继续开发,签约状态查看如下所示,注意:未完成签约的应用是无法接入成功的. 3.配置

支付宝app支付服务器签名代码(C#)

1,引入支付宝的sdk(AopSdk) 支付宝接口文档网站可下载,注意下载C#版本: 2,代码写的比较简单 public static string RSASign(string OrderNo,decimal Money,string bodyp,string subjectp) { string publicKeyPem = ;//支付宝公钥  string privateKeyPem = ;//商户私钥 string out_trade_no = OrderNo;//订单号 double