最近在使用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能够直接使用。git
支付宝有比较多的支付产品,好比当面付、APP支付、手机网站支付、电脑网站支付等,本次讲的是电脑网站支付。github
若是你没有时间阅读文章,能够直接从github获取Demo原来进行查看,很是简单。github: https://github.com/stulzq/Alipay.Demo.PCPayment算法
新建一个ASP.NET Core 2.0 MVC项目json
因为我在开发的时候支付接口并无申请下来,因此使用的是支付宝沙箱环境来进行开发的。api
支付宝沙箱环境介绍:蚂蚁沙箱环境(Beta)是协助开发者进行接口功能开发及主要功能联调的辅助环境。沙箱环境模拟了开放平台部分产品的主要功能和主要逻辑,在开发者应用上线审核前,开发者能够根据自身需求,先在沙箱环境中了解、组合和调试各类开放接口,进行开发调通工做,从而帮助开发者在应用上线审核完成后,能更快速、更顺利的进行线上调试和验收工做。
若是在签约或建立应用前想要进行集成测试,可使用沙箱环境。
沙箱环境支持使用我的帐号或企业帐号登录。app
沙箱环境地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info异步
这里所使用的RSA密钥标准为PKCS1,须要特别注意。async
能够下载我写的密钥生成器:https://github.com/dotnetcore/Alipay.AopSdk.Core/tree/dev/tool工具
运行能够直接生成长度为2048标准为PKCS1的公钥和私钥。post
或者使用下载支付宝官方提供的密钥生成工具来进行生,详细介绍:https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=105971&docType=1
咱们生成密钥以后,须要到支付宝后台设置应用公钥,就是咱们生成的公钥。
设置以后,支付宝会给咱们一个支付宝公钥,保存这个支付宝公钥
这个支付宝公钥和咱们本身生成的公钥是不同的,咱们在配置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"; }
商户私钥即咱们本身生成的私钥,公钥就是支付宝公钥这里必定要注意,别用错了。这里的公钥私钥直接填写字符串便可。
签名方式推荐使用RSA2
,使用RSA2,支付宝会用SHA256withRsa算法进行接口调用时的验签(不限制密钥长度)。
编码格式,若是咱们是直接配置的字符串(公钥、私钥),那么就是咱们代码的编码,若是使用的是文件(公钥、私钥),那么就是文件的编码。
完成配置以下:
官方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); }
运行:
支付宝同步回调通知(支付成功后跳转到商户网站),是不可靠的,因此这里必须使用异步通知来获取支付结果,异步通知即支付宝主动请求咱们提供的地址,咱们根据请求数据来校验,获取支付结果。
/// <summary> /// 支付异步回调通知 需配置域名 由于是支付宝主动post请求这个action 因此要经过域名访问或者公网ip /// </summary> public async void Notify() { /* 实际验证过程建议商户添加如下校验。 一、商户须要验证该通知数据中的out_trade_no是否为商户系统中建立的订单号, 二、判断total_amount是否确实为该订单的实际金额(即商户订单建立时的金额), 三、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操做方(有的时候,一个商户可能有多个seller_id/seller_email) 四、验证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() { /* 实际验证过程建议商户添加如下校验。 一、商户须要验证该通知数据中的out_trade_no是否为商户系统中建立的订单号, 二、判断total_amount是否确实为该订单的实际金额(即商户订单建立时的金额), 三、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操做方(有的时候,一个商户可能有多个seller_id/seller_email) 四、验证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); }
最重要的:
本文Demo:https://github.com/stulzq/Alipay.Demo.PCPayment
若是有问题欢迎提出!