1. 程式人生 > >.Net後臺實現支付寶APP支付

.Net後臺實現支付寶APP支付

void 支付平臺 固定 ces rand threading ade 簽名 ask

前面討論了微信支付,接下來聊聊支付寶的APP支付(新款支付寶支付)。其實這些支付原理都一樣,只不過具體到每個支付平臺,所使用的支付配置參數不同,返回至支付端的下單參數也不同。

話不多說,直接上代碼。

在App.Pay項目中使用NuGet管理器添加引用Alipay.AopSdk,也可以不添加引用,將官方SDK源碼放至項目中。

技術分享圖片

添加完引用後,我們就可以開工了,新建文件夾AliPay,在文件夾中新建AliPayConfig類,存放支付寶APP支付所需的參數,同樣,這些參數我也放在了配置文件中。

技術分享圖片
 1 using System;
 2 using System.Collections.Generic;
3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Web.Configuration; 7 8 namespace App.Pay.AliPay 9 { 10 public class AliPayConfig 11 { 12 //支付寶網關地址 13 public static string serviceUrl = WebConfigurationManager.AppSettings["aliServiceUrl
"].ToString(); 14 15 //應用ID 16 public static string appId = WebConfigurationManager.AppSettings["aliAppId"].ToString(); 17 18 //開發者私鑰,由開發者自己生成 19 public static string privateKey = WebConfigurationManager.AppSettings["aliPrivateKey"].ToString(); 20 21 //支付寶的應用公鑰 22
public static string publicKey = WebConfigurationManager.AppSettings["aliPublicKey"].ToString(); 23 24 //支付寶的支付公鑰 25 public static string payKey = WebConfigurationManager.AppSettings["aliPayKey"].ToString(); 26 27 //服務器異步通知頁面路徑 28 public static string notify_url = WebConfigurationManager.AppSettings["aliNotifyUrl"].ToString(); 29 30 //頁面跳轉同步通知頁面路徑 31 public static string return_url = WebConfigurationManager.AppSettings["aliReturnUrl"].ToString(); 32 33 //參數返回格式,只支持json 34 public static string format = WebConfigurationManager.AppSettings["aliFormat"].ToString(); 35 36 // 調用的接口版本,固定為:1.0 37 public static string version = WebConfigurationManager.AppSettings["aliVersion"].ToString(); 38 39 // 商戶生成簽名字符串所使用的簽名算法類型,目前支持RSA2和RSA,推薦使用RSA2 40 public static string signType = WebConfigurationManager.AppSettings["aliSignType"].ToString(); 41 42 // 字符編碼格式 目前支持utf-8 43 public static string charset = WebConfigurationManager.AppSettings["aliCharset"].ToString(); 44 45 // false 表示不從文件加載密鑰 46 public static bool keyFromFile = false; 47 48 // 日誌記錄 49 public static string LogPath = WebConfigurationManager.AppSettings["AliLog"].ToString(); 50 } 51 }
View Code

支付寶支付中有個沙箱測試環境,我們可以先在沙箱環境下調通整個流程(沙箱支付寶裏面的錢是虛擬的哦)。介紹一下這幾個支付參數。

  ①aliServiceUrl支付寶網關地址,固定不變的,沙箱環境下用沙箱的,正式環境下用正式的。

  ②aliAppId支付寶APPID,aliPrivateKey支付寶應用私鑰,aliPublicKey支付寶應用公鑰,aliPayKey支付寶公鑰

    aliPublicKey和aliPayKey是不一樣的,一個是應用公鑰,一個是支付寶公鑰,回調接口中驗簽使用的是支付寶公鑰

  ③aliNotifyUrl服務器通知,aliReturnUrl網頁重定向通知(暫時沒有用到)。主要使用到的還是aliNotifyUrl,買家付完款後(trade_status=WAIT_SELLER_SEND_GOODS),支付寶服務端會自動向商戶後臺發送支付回調通知,同樣,商戶在支付回調通知中修改訂單相關狀態,反饋給支付寶success,表示成功接收到回調,這個狀態下支付寶不會再繼續通知商戶後臺。

  ④aliFormat、aliVersion、aliSignType、aliCharset這幾個參數都是固定不變的,簽名的時候使用。

技術分享圖片
 1 <!--支付寶app支付-->
 2     <add key="aliServiceUrl" value=""/>
 3     <add key="aliAppId" value="" />
 4     <add key="aliPrivateKey" value=""/>
 5     <add key="aliPublicKey" value="" />
 6     <add key="aliPayKey" value="" />
 7     <add key="aliNotifyUrl" value="" />
 8     <add key="aliReturnUrl" value="" />
 9     <add key="aliFormat" value="json" />
10     <add key="aliVersion" value="1.0" />
11     <add key="aliSignType" value="RSA2" />
12     <add key="aliCharset" value="utf-8" />
View Code

新建AliPay類

技術分享圖片
 1 using Aop.Api;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 
 8 namespace App.Pay.AliPay
 9 {
10     public class AliPay
11     {
12         public static IAopClient GetAlipayClient()
13         {
14             string serviceUrl = AliPayConfig.serviceUrl;
15 
16             string appId = AliPayConfig.appId;
17 
18             string privateKey = AliPayConfig.privateKey;
19 
20             string publivKey = AliPayConfig.publicKey;
21 
22             string format = AliPayConfig.format;
23 
24             string version = AliPayConfig.version;
25 
26             string signType = AliPayConfig.signType;
27 
28             string charset = AliPayConfig.charset;
29 
30             bool keyFromFile = AliPayConfig.keyFromFile;
31 
32 
33             IAopClient client = new DefaultAopClient(serviceUrl, appId, privateKey, format, version, signType, publivKey, charset, keyFromFile); ;
34 
35             return client;
36         }
37     }
38 }
View Code

接下來就是業務中的具體調用

技術分享圖片
  1 using Aop.Api;
  2 using Aop.Api.Domain;
  3 using Aop.Api.Request;
  4 using Aop.Api.Response;
  5 using Aop.Api.Util;
  6 using App.Common.Extension;
  7 using App.Pay.AliPay;
  8 using System;
  9 using System.Collections.Generic;
 10 using System.Collections.Specialized;
 11 using System.Linq;
 12 using System.Web;
 13 using System.Web.Mvc;
 14 
 15 namespace App.WebTest.Controllers
 16 {
 17     public class AliPayController : BaseController
 18     {
 19         /// <summary>
 20         /// 訂單編號
 21         /// </summary>
 22         /// <param name="oidStr"></param>
 23         /// <returns></returns>
 24         public ActionResult AliPay(string oidStr)
 25         {
 26             #region 驗證訂單有效
 27 
 28             if (string.IsNullOrEmpty(oidStr))
 29             {
 30                 return Json(false, "OrderError");
 31             }
 32 
 33             int[] oIds = Serialize.JsonTo<int[]>(oidStr);
 34 
 35             decimal payPrice = 0;
 36 
 37             ///訂單驗證,統計訂單總金額
 38 
 39             #endregion
 40 
 41             #region 統一下單
 42             try
 43             {
 44                 var notify_url = AliPayConfig.notify_url;
 45                 var return_url = AliPayConfig.return_url;
 46                 IAopClient client = Pay.AliPay.AliPay.GetAlipayClient();
 47                 AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
 48                 //SDK已經封裝掉了公共參數,這裏只需要傳入業務參數。以下方法為sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。
 49                 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
 50                 model.Subject = "商品購買";
 51                 model.TotalAmount = payPrice.ToString("F2");
 52                 model.ProductCode = "QUICK_MSECURITY_PAY";
 53                 Random rd = new Random();
 54                 var payNum = DateTime.Now.ToString("yyyyMMddHHmmss") + rd.Next(0, 1000).ToString().PadLeft(3, 0);
 55                 model.OutTradeNo = payNum;
 56                 model.TimeoutExpress = "30m";
 57                 request.SetBizModel(model);
 58                 request.SetNotifyUrl(notify_url);
 59                 //request.SetReturnUrl(return_url);
 60                 //這裏和普通的接口調用不同,使用的是sdkExecute
 61                 AlipayTradeAppPayResponse response = client.SdkExecute(request);
 62 
 63                 //統一下單
 64                 //OrderBll.Value.UpdateOrderApp(oIds, payNum);
 65 
 66                 return Json(true, new { response.Body }, "OK");
 67             }
 68             catch (Exception ex)
 69             {
 70                 return Json(new { Result = false, msg = "缺少參數" });
 71             }
 72             #endregion
 73         }
 74 
 75         /// <summary>
 76         /// 頁面跳轉同步通知頁面
 77         /// </summary>
 78         /// <returns></returns>
 79         public ActionResult ReturnUrl()
 80         {
 81             Pay.Log Log = new Pay.Log(Pay.AliPay.AliPayConfig.LogPath);
 82             Log.Info("ReturnUrl", "支付頁面同步回調");
 83             //將同步通知中收到的所有參數都存放到map中
 84             IDictionary<string, string> map = GetRequestGet();
 85             if (map.Count > 0) //判斷是否有帶返回參數
 86             {
 87                 try
 88                 {
 89                     //支付寶的公鑰
 90                     string alipayPublicKey = AliPayConfig.payKey;
 91                     string signType = AliPayConfig.signType;
 92                     string charset = AliPayConfig.charset;
 93                     bool keyFromFile = false;
 94                     // 獲取支付寶GET過來反饋信息  
 95                     bool verify_result = AlipaySignature.RSACheckV1(map, alipayPublicKey, charset, signType, keyFromFile);
 96                     if (verify_result)
 97                     {
 98                         // 驗證成功                        
 99                         return Json(new { Result = true, msg = "驗證成功" });
100                     }
101                     else
102                     {
103                         Log.Error("AliPayNotifyUrl", "支付驗證失敗");
104                         return Json(new { Result = false, msg = "驗證失敗" });
105                     }
106                 }
107                 catch (Exception e)
108                 {
109                     //throw new Exception(e.Message);
110                     return Json(new { Result = false, msg = "驗證失敗" });
111                     Log.Error("AliPayNotifyUrl", "支付驗證失敗");
112                 }
113             }
114             else
115             {
116                 return Json(new { Result = false, msg = "無返回參數" });
117             }
118         }
119 
120         /// <summary>
121         /// 服務器異步通知頁面
122         /// </summary>
123         public void AliPayNotifyUrl()
124         {
125             Pay.Log Log = new Pay.Log(AliPayConfig.LogPath);
126             Log.Info("AliPayNotifyUrl", "支付頁面異步回調");
127             IDictionary<string, string> map = GetRequestPost();
128 
129             if (map.Count > 0)
130             {
131                 try
132                 {
133                     string alipayPublicKey = AliPayConfig.payKey;
134                     string signType = AliPayConfig.signType;
135                     string charset = AliPayConfig.charset;
136                     bool keyFromFile = false;
137 
138                     bool verify_result = AlipaySignature.RSACheckV1(map, alipayPublicKey, charset, signType, keyFromFile);
139                     Log.Info("AliPayNotifyUrl驗簽", verify_result + "");
140 
141                     //驗簽成功後,按照支付結果異步通知中的描述,對支付結果中的業務內容進行二次校驗,校驗成功後再response中返回success並繼續商戶自身業務處理,校驗失敗返回false
142                     if (verify_result)
143                     {
144                         //商戶訂單號
145                         string out_trade_no = map["out_trade_no"];
146                         //支付寶交易號
147                         string trade_no = map["trade_no"];
148                         //交易創建時間
149                         string gmt_create = map["gmt_create"];
150                         //交易付款時間
151                         string gmt_payment = map["gmt_payment"];
152                         //通知時間
153                         string notify_time = map["notify_time"];
154                         //通知類型  trade_status_sync
155                         string notify_type = map["notify_type"];
156                         //通知校驗ID
157                         string notify_id = map["notify_id"];
158                         //開發者的app_id
159                         string app_id = map["app_id"];
160                         //賣家支付寶用戶號
161                         string seller_id = map["seller_id"];
162                         //買家支付寶用戶號
163                         string buyer_id = map["buyer_id"];
164                         //實收金額
165                         string receipt_amount = map["receipt_amount"];
166                         //交易狀態
167                         string return_code = map["trade_status"];
168 
169                         //交易狀態TRADE_FINISHED的通知觸發條件是商戶簽約的產品不支持退款功能的前提下,買家付款成功;
170                         //或者,商戶簽約的產品支持退款功能的前提下,交易已經成功並且已經超過可退款期限
171                         //狀態TRADE_SUCCESS的通知觸發條件是商戶簽約的產品支持退款功能的前提下,買家付款成功
172                         if (return_code == "TRADE_FINISHED" || return_code == "TRADE_SUCCESS")
173                         {
174                             string msg;
175 
176                             Log.Error("AliPayNotifyUrl", receipt_amount + "==" + trade_no + "==" + return_code + "==" + out_trade_no + "==" + gmt_payment);
177 
178                             //判斷該筆訂單是否在商戶網站中已經做過處理
179                             ///支付回調的業務處理
180                             //bool res = OrderBll.Value.CompleteAliPay(receipt_amount, trade_no, return_code, out_trade_no, gmt_payment, out msg);
181                             bool res = true;
182 
183                             if (res == false)
184                             {
185                                 Response.Write("添加支付信息失敗!");
186                             }
187                             Log.Error("AliPayNotifyUrl", "支付成功");
188                             Response.Write("success");  //請不要修改或刪除
189                         }
190                     }
191                     else
192                     {
193                         //驗證失敗
194                         Log.Error("AliPayNotifyUrl", "支付驗證失敗");
195                         Response.Write("驗證失敗!");
196                     }
197                 }
198                 catch (Exception e)
199                 {
200                     Response.Write("添加支付信息失敗!");
201                     Log.Error("AliPayNotifyUrl", "添加支付信息失敗");
202                 }
203             }
204             else
205             {
206                 //無返回參數
207                 Response.Write("無返回參數!");
208                 Log.Error("AliPayNotifyUrl", "無返回參數");
209             }
210         }
211         //[AllowUser]
212         //public ActionResult TestAliPay()
213         //{
214 
215         //    var receipt_amount = "0.01";
216         //    var trade_no = "20181226220013.......";
217         //    var return_code = "TRADE_SUCCESS";
218         //    var out_trade_no = "20181226103124129";
219         //    var gmt_payment = "2018-12-26 10:31:29";
220 
221         //    string msg = "";
222         //    bool res = OrderBll.Value.CompleteAliPay(receipt_amount, trade_no, return_code, out_trade_no, gmt_payment, out msg);
223 
224         //    return Json(res);
225         //}
226 
227         /// <summary>
228         /// 獲取支付寶Get過來的通知消息,並以“參數名=參數值”的形式組成數組
229         /// </summary>
230         /// <returns></returns>
231         public IDictionary<string, string> GetRequestGet()
232         {
233             Pay.Log Log = new Pay.Log(Pay.AliPay.AliPayConfig.LogPath);
234             int i = 0;
235             IDictionary<string, string> sArry = new Dictionary<string, string>();
236             NameValueCollection coll;
237             coll = Request.QueryString;
238 
239             String[] requstItem = coll.AllKeys;
240 
241             for (i = 0; i < requstItem.Length; i++)
242             {
243                 Log.Info("GetRequestGet", requstItem[i] + ":" + Request.QueryString[requstItem[i]]);
244                 sArry.Add(requstItem[i], Request.QueryString[requstItem[i]]);
245             }
246 
247             return sArry;
248         }
249 
250         /// <summary>
251         /// 獲取支付寶POST過來通知消息,並以“參數名=參數值”的形式組成數組
252         /// </summary>
253         /// <returns>request回來的信息組成的數組</returns>
254         public IDictionary<string, string> GetRequestPost()
255         {
256             Pay.Log Log = new Pay.Log(Pay.AliPay.AliPayConfig.LogPath);
257             int i = 0;
258             IDictionary<string, string> sArray = new Dictionary<string, string>();
259             NameValueCollection coll;
260 
261             //Load Form variables into NameValueCollection variable.
262             coll = Request.Form;
263 
264             // Get names of all forms into a string array.
265             String[] requestItem = coll.AllKeys;
266             for (i = 0; i < requestItem.Length; i++)
267             {
268                 Log.Info("GetRequestPost", requestItem[i] + ":" + Request.Form[requestItem[i]]);
269                 sArray.Add(requestItem[i], Request.Form[requestItem[i]]);
270             }
271 
272             return sArray;
273         }
274     }
275 }
View Code

.Net後臺實現支付寶APP支付