前面討論了微信支付,接下來聊聊支付寶的APP支付(新款支付寶支付)。其實這些支付原理都同樣,只不過具體到每一個支付平臺,所使用的支付配置參數不一樣,返回至支付端的下單參數也不一樣。算法
話很少說,直接上代碼。json
在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 }
支付寶支付中有個沙箱測試環境,咱們能夠先在沙箱環境下調通整個流程(沙箱支付寶裏面的錢是虛擬的哦)。介紹一下這幾個支付參數。微信
①aliServiceUrl支付寶網關地址,固定不變的,沙箱環境下用沙箱的,正式環境下用正式的。app
②aliAppId支付寶APPID,aliPrivateKey支付寶應用私鑰,aliPublicKey支付寶應用公鑰,aliPayKey支付寶公鑰dom
aliPublicKey和aliPayKey是不同的,一個是應用公鑰,一個是支付寶公鑰,回調接口中驗籤使用的是支付寶公鑰異步
③aliNotifyUrl服務器通知,aliReturnUrl網頁重定向通知(暫時沒有用到)。主要使用到的仍是aliNotifyUrl,買家付完款後(trade_status=WAIT_SELLER_SEND_GOODS),支付寶服務端會自動向商戶後臺發送支付回調通知,一樣,商戶在支付回調通知中修改訂單相關狀態,反饋給支付寶success,表示成功接收到回調,這個狀態下支付寶不會再繼續通知商戶後臺。ide
④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" />
新建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 }
接下來就是業務中的具體調用
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 }