ASP.NET Core 2.0 使用支付宝PC网站支付实现代码
前言
最近在使用asp.net core来进行开发,刚好有个接入支付宝支付的需求,百度了一下没找到相关的资料,看了官方的sdk以及demo都还是.net framework的,所以就先根据官方sdk的源码,用.net standard 2.0 实现了支付宝服务端sdk,alipay.aopsdk.core(github:https://github.com/stulzq/alipay.aopsdk.core) ,支持.net core 2.0。为了使用方便,已上传至nuget可以直接使用。
支付宝有比较多的支付产品,比如当面付、app支付、手机网站支付、电脑网站支付等,本次讲的是电脑网站支付。
如果你没有时间阅读文章,可以直接从github获取demo原来进行查看,非常简单。github: https://github.com/stulzq/alipay.demo.pcpayment
创建项目
新建一个asp.net core 2.0 mvc项目
配置
由于我在开发的时候支付接口并没有申请下来,所以使用的是支付宝沙箱环境来进行开发的。
支付宝沙箱环境介绍:蚂蚁沙箱环境(beta)是协助开发者进行接口功能开发及主要功能联调的辅助环境。沙箱环境模拟了开放平台部分产品的主要功能和主要逻辑,在开发者应用上线审核前,开发者可以根据自身需求,先在沙箱环境中了解、组合和调试各种开放接口,进行开发调通工作,从而帮助开发者在应用上线审核完成后,能更快速、更顺利的进行线上调试和验收工作。
如果在签约或创建应用前想要进行集成测试,可以使用沙箱环境。
沙箱环境支持使用个人账号或企业账号登陆。
沙箱环境地址:https://openhome.alipay.com/platform/appdaily.htm?tab=info
1.生成密钥
下载支付宝官方提供的密钥生成工具来进行生成,详细介绍:https://doc.open.alipay.com/docs/doc.htm?treeid=291&articleid=105971&doctype=1
2.设置应用公钥
我们生成密钥之后,需要到支付宝后台设置应用公钥,就是我们生成的公钥。
设置之后,支付宝会给我们一个支付宝公钥,保存这个支付宝公钥
这个支付宝公钥和我们自己生成的公钥是不一样的,我们在配置sdk时用的公钥就是支付宝公钥
3.配置sdk
新建一个config
类,在里面存储我们的配置。
public class config{ // 应用id,您的appid public static string appid = ""; // 支付宝网关 public static string gatewayurl = ""; // 商户私钥,您的原始格式rsa私钥 public static string privatekey = ""; // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keymanage.htm 对应appid下的支付宝公钥。 public static string alipaypublickey = ""; // 签名方式 public static string signtype = "rsa2"; // 编码格式 public static string charset = "utf-8";}
应用id和支付宝网关都可以在支付宝后台查看。
商户私钥即我们自己生成的私钥,公钥就是支付宝公钥这里一定要注意,别用错了。这里的公钥私钥直接填写字符串即可。
签名方式推荐使用rsa2
,使用rsa2,支付宝会用sha256withrsa算法进行接口调用时的验签(不限制密钥长度)。
编码格式,如果我们是直接配置的字符串(公钥、私钥),那么就是我们代码的编码,如果使用的是文件(公钥、私钥),那么就是文件的编码。
完成配置如下:
添加sdk
官方sdk的源码(.net framework),用.net standard 2.0 实现的支付宝服务端sdk,alipay.aopsdk.core(github:https://github.com/stulzq/alipay.aopsdk.core) ,支持.net core 2.0。
通过nuget安装:install-package alipay.aopsdk.core
支付
添加一个控制器 paycontroller
/// 发起支付请求/// </summary>/// <param name="tradeno">外部订单号,商户网站订单系统中唯一的订单号</param>/// <param name="subject">订单名称</param>/// <param name="totalamout">付款金额</param>/// <param name="itembody">商品描述</param>/// <returns></returns>[httppost] public void payrequest(string tradeno,string subject,string totalamout,string itembody){ defaultaopclient client = new defaultaopclient(config.gatewayurl, config.appid, config.privatekey, "json", "2.0", config.signtype, config.alipaypublickey, config.charset, false); // 组装业务参数model alipaytradepagepaymodel model = new alipaytradepagepaymodel(); model.body = itembody; model.subject = subject; model.totalamount = totalamout; model.outtradeno = tradeno; model.productcode = "fast_instant_trade_pay"; alipaytradepagepayrequest request = new alipaytradepagepayrequest(); // 设置同步回调地址 request.setreturnurl("http://localhost:5000/pay/callback"); // 设置异步通知接收地址 request.setnotifyurl(""); // 将业务model载入到request request.setbizmodel(model); var response = client.sdkexecute(request); console.writeline($"订单支付发起成功,订单号:{tradeno}"); //跳转支付宝支付 response.redirect(config.gatewayurl + "?" + response.body);}
运行:
图1
图2
图3
支付异步回调通知
支付宝同步回调通知(支付成功后跳转到商户网站),是不可靠的,所以这里必须使用异步通知来获取支付结果,异步通知即支付宝主动请求我们提供的地址,我们根据请求数据来校验,获取支付结果。
/// <summary>/// 支付异步回调通知 需配置域名 因为是支付宝主动post请求这个action 所以要通过域名访问或者公网ip/// </summary>public async void notify(){ /* 实际验证过程建议商户添加以下校验。 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号, 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额), 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email) 4、验证app_id是否为该商户本身。 */ dictionary<string, string> sarray = getrequestpost(); if (sarray.count != 0) { bool flag = alipaysignature.rsacheckv1(sarray, config.alipaypublickey,config.charset, config.signtype, false); if (flag) { //交易状态 //判断该笔订单是否在商户网站中已经做过处理 //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序 //请务必判断请求时的total_amount与通知时获取的total_fee为一致的 //如果有做过处理,不执行商户的业务程序 //注意: //退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知 console.writeline(request.form["trade_status"]); await response.writeasync("success"); } else { await response.writeasync("fail"); } }}
同步回调
同步回调即支付成功跳转回商户网站
运行:
/// <summary>/// 支付同步回调/// </summary>[httpget]public iactionresult callback(){ /* 实际验证过程建议商户添加以下校验。 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号, 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额), 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email) 4、验证app_id是否为该商户本身。 */ dictionary<string, string> sarray = getrequestget(); if (sarray.count != 0) { bool flag = alipaysignature.rsacheckv1(sarray, config.alipaypublickey, config.charset, config.signtype, false); if (flag) { console.writeline($"同步验证通过,订单号:{sarray["out_trade_no"]}"); viewdata["payresult"] = "同步验证通过"; } else { console.writeline($"同步验证失败,订单号:{sarray["out_trade_no"]}"); viewdata["payresult"] = "同步验证失败"; } } return view(); }
订单查询
查询订单当前状态:已付款、未付款等等。
运行:
订单退款
[httppost]public jsonresult query(string tradeno, string alipaytradeno){ defaultaopclient client = new defaultaopclient(config.gatewayurl, config.appid, config.privatekey, "json", "2.0", config.signtype, config.alipaypublickey, config.charset, false); alipaytradequerymodel model = new alipaytradequerymodel(); model.outtradeno = tradeno; model.tradeno = alipaytradeno; alipaytradequeryrequest request = new alipaytradequeryrequest(); request.setbizmodel(model); var response = client.execute(request); return json(response.body);}
退回该订单金额。
运行:
/// <summary> /// 订单退款 /// </summary>/// <param name="tradeno">商户订单号</param>/// <param name="alipaytradeno">支付宝交易号</param>/// <param name="refundamount">退款金额</param>/// <param name="refundreason">退款原因</param>/// <param name="refundno">退款单号</param>/// <returns></returns>[httppost]public jsonresult refund(string tradeno,string alipaytradeno,string refundamount,string refundreason,string refundno){ defaultaopclient client = new defaultaopclient(config.gatewayurl, config.appid, config.privatekey, "json", "2.0", config.signtype, config.alipaypublickey, config.charset, false); alipaytraderefundmodel model = new alipaytraderefundmodel(); model.outtradeno = tradeno; model.tradeno = alipaytradeno; model.refundamount = refundamount; model.refundreason = refundreason; model.outrequestno = refundno; alipaytraderefundrequest request = new alipaytraderefundrequest(); request.setbizmodel(model); var response = client.execute(request); return json(response.body);}
退款查询
查询退款信息。
运行:
/// <summary> /// 退款查询 /// </summary> /// <param name="tradeno">商户订单号</param> /// <param name="alipaytradeno">支付宝交易号</param> /// <param name="refundno">退款单号</param> /// <returns></returns> [httppost] public jsonresult refundquery(string tradeno,string alipaytradeno,string refundno) { defaultaopclient client = new defaultaopclient(config.gatewayurl, config.appid, config.privatekey, "json", "2.0", config.signtype, config.alipaypublickey, config.charset, false); if (string.isnullorempty(refundno)) { refundno = tradeno; } alipaytradefastpayrefundquerymodel model = new alipaytradefastpayrefundquerymodel(); model.outtradeno = tradeno; model.tradeno = alipaytradeno; model.outrequestno = refundno; alipaytradefastpayrefundqueryrequest request = new alipaytradefastpayrefundqueryrequest(); request.setbizmodel(model); var response = client.execute(request); return json(response.body); }
订单关闭
对一定时间以后没有进行付款的订单进行关闭,订单状态需为:待付款,已完成支付的订单无法关闭。
运行:
/// <summary> /// 关闭订单 /// </summary> /// <param name="tradeno">商户订单号</param> /// <param name="alipaytradeno">支付宝交易号</param> /// <returns></returns> [httppost] public jsonresult orderclose(string tradeno, string alipaytradeno) { defaultaopclient client = new defaultaopclient(config.gatewayurl, config.appid, config.privatekey, "json", "2.0", config.signtype, config.alipaypublickey, config.charset, false); alipaytradeclosemodel model = new alipaytradeclosemodel(); model.outtradeno = tradeno; model.tradeno = alipaytradeno; alipaytradecloserequest request = new alipaytradecloserequest(); request.setbizmodel(model); var response = client.execute(request); return json(response.body); }
地址集合支付宝api文档支付宝沙箱环境支付宝密钥生成工具支付宝服务端sdk源码支付宝服务端sdk nuget
最重要的: