zoukankan      html  css  js  c++  java
  • 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.生成密钥

    这里所使用的RSA密钥标准为PKCS1,需要特别注意。

    可以下载我写的密钥生成器:https://github.com/dotnetcore/Alipay.AopSdk.Core/tree/dev/tool

    运行可以直接生成长度为2048标准为PKCS1的公钥和私钥。

    或者使用下载支付宝官方提供的密钥生成工具来进行生,详细介绍: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);
    }
    

    地址集合

    最重要的:

    本文Demo:https://github.com/stulzq/Alipay.Demo.PCPayment

    如果有问题欢迎提出!

  • 相关阅读:
    .net中的委托
    GridView, DataList and ListBox 行 单击与双击事件处理
    ChineseCalendar类[转]
    数据契约(DataContract)
    XPath 语法(复习)
    正则表达式学习笔记
    瑞星笔试:现场上机做题[转]
    发送带有附件的电子邮件使用 Cdosys.dll 库
    DataContractJsonSerializer 类 操作json类型数据
    i guess a bug on Castle
  • 原文地址:https://www.cnblogs.com/stulzq/p/7606164.html
Copyright © 2011-2022 走看看