最近在使用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
若是有問題歡迎提出!