前言
最近有點空余時間,所以,就研究了一下APP支付。前面很早就搞完APP的微信支付了,但是由於時間上和應用上的情況,支付寶一直沒空去研究。然后等我空了的時候,發現支付寶居然升級了支付邏輯,雖然目前還兼容老的方法,但是新的既然出來了,肯定研究新的了。但是網上幾乎都是舊的方法,所以,唯有自己看官方的文檔,慢慢一步一步研究了。在研究的過程中,發現,他跟微信支付的差別蠻大的。好了廢話不多說了,下面直接來干貨。
- 首先,你得去螞蟻金服開放平台申請一個應用,地址:https://openhome.alipay.com注冊一個應用,如下圖:

應用申請下來之后,需要申請功能,我們這里用到的是“APP支付”功能。如下圖:

如果需要查看相關的文檔,那就點擊“APP支付”就可以跳轉到相關的文檔,這里我直接給出APP需要看到的文檔,地址:
https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.J9S7XU&treeId=204&articleId=105465&docType=1
如下圖:

我們在編寫服務端的時候,需要用到兩個參數,一個是APPID,這個上面的圖里面有,還有一個就是密鑰,這個是通過簽名工具生成,可以通過下面這個地址下載工具,然后生成,地址:
https://doc.open.alipay.com/doc2/detail.htm?treeId=200&articleId=105351&docType=1

下載這個工具,然后解壓,雙擊“
支付寶RAS密鑰生成器SHAwithRSA1024_V1.0.bat
”生成即可,這里要注意:
TIPS:
工具不支持含中文或空格的路徑,請下載到英文目錄下使用。
打開工具后,如下圖:

先“生成密鑰”,然后再復制公鑰,然后把公鑰復制到平台,如下圖:

再保存,如下圖:

然后再驗證公鑰的正確性,這里,可以寫個小工具來驗證,方法如下:
/// <summary>
/// 測試公鑰是否對
/// </summary>
/// <returns></returns>
public string testsign()
{
string privtekey = Config.privtekey;//這個就是生成器里面的那個私鑰,第一個大框框那里的.
string data = "a=123";//平台上提供的串
string sign = RSAFromPkcs8.sign(data, privtekey, "utf-8");
return sign;
}
然后再把這個sign的值,復制出來,然后再點擊“驗證公鑰正確性”,如下圖:

然后輸入你的“sign”的值:
點擊“驗證”后,如果提示驗證通過,那么你這個簽名的方式就是對了,如下圖:

再點擊“保存”即可。
接下來,我就寫一下服務端生成相應的串的方法,全部貼出來,方便大家模仿吧,其實大家按照下面這個圖,慢慢研究,也可以的,如下圖:

最后,我們要給回到APP的參數是這個,只要我們按照規則返回即可。下面,我把方法貼出:
public class AliPayController : Controller
{
public Dictionary<string, string> PayInfo = new Dictionary<string, string>();
//
// GET: /AliPay/
public ActionResult Index()
{
testsign();
GetPayInfo("0.01");
return View();
}
/// <summary>
/// 測試公鑰是否對
/// </summary>
/// <returns></returns>
public string testsign()
{
string privtekey = Config.privtekey;//這個就是生成器里面的那個私鑰,第一個大框框那里的.
string data = "a=123";//平台上提供的串
string sign = RSAFromPkcs8.sign(data, privtekey, "utf-8");
return sign;
}
/// <summary>
/// 獲取支付信息
/// </summary>
/// <param name="_amount"></param>
/// <returns></returns>
public string GetPayInfo(string _amount)//_amount:付款金額
{
string strJson = string.Empty;
try
{
string orderInfo = GetOrderInfoWithOutEncode(_amount);
// 對訂單做RSA 簽名
string sign = RSAFromPkcs8.sign(orderInfo, Config.privtekey, "utf-8");
//僅需對sign做URL編碼
sign = HttpUtility.UrlEncode(sign, Encoding.UTF8);
string payInfo = GetOrderInfoWithEncode() + "&sign=" + sign;
strJson = payInfo.Replace("+", "%20");//日期那里會有一個空格(2017-01-05 11:11:11)轉化為+,所以這里要替換一下
FileLog.WriteLog("支付寶串:" + strJson);
}
catch (Exception ex)
{
FileLog.WriteLog(ex.ToString());
}
return strJson;
}
/// <summary>
/// 不包含Encode的字符串拼接
/// </summary>
/// <param name="price"></param>
/// <returns></returns>
public string GetOrderInfoWithOutEncode(string price)
{
PayInfo.Add("app_id", Config.app_id);
PayInfo.Add("biz_content", GetBizContent(price));
PayInfo.Add("charset", "utf-8");
PayInfo.Add("format", "json");
PayInfo.Add("method", "alipay.trade.app.pay");
PayInfo.Add("notify_url", "http://wxpay.lmx.ren/ResultNotify");
PayInfo.Add("sign_type", "RSA");
PayInfo.Add("timestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
PayInfo.Add("version", "1.0");
string strUrl = BuildQueryWithOutEncode(PayInfo);
return strUrl;
}
/// <summary>
/// 包含Encode的字符串拼接
/// </summary>
/// <param name="price"></param>
/// <returns></returns>
public string GetOrderInfoWithEncode()
{
string strUrl = BuildQuery(PayInfo, "utf-8");
return strUrl;
}
/// <summary>
/// 獲取支付內容詳情
/// </summary>
/// <param name="total_amount"></param>
/// <returns></returns>
public string GetBizContent(string total_amount)
{
Dictionary<string, string> biz_content_info = new Dictionary<string, string>();
biz_content_info.Add("timeout_express", "30m");//該筆訂單允許的最晚付款時間,逾期將關閉交易。
biz_content_info.Add("seller_id", "");//收款支付寶用戶ID。 如果該值為空,則默認為商戶簽約賬號對應的支付寶用戶ID
biz_content_info.Add("product_code", "QUICK_MSECURITY_PAY");//銷售產品碼,商家和支付寶簽約的產品碼,為固定值QUICK_MSECURITY_PAY
biz_content_info.Add("total_amount", "0.01");//訂單總金額,單位為元,精確到小數點后兩位,取值范圍[0.01,100000000]
biz_content_info.Add("subject", "Iphone7 128G");//商品的標題/交易標題/訂單標題/訂單關鍵字等。
biz_content_info.Add("body", "最新款的手機啦");//對一筆交易的具體描述信息。如果是多種商品,請將商品描述字符串累加傳給body。
biz_content_info.Add("out_trade_no", DateTime.Now.ToString("yyyyMMddHHmmssffffff"));//商戶網站唯一訂單號
string strBizContent = JsonHelper.Serialize(biz_content_info);
return strBizContent;
}
/// <summary>
/// 組裝普通文本請求參數(帶Encode)。
/// </summary>
/// <param name="parameters">Key-Value形式請求參數字典</param>
/// <returns>URL編碼后的請求數據</returns>
public static string BuildQuery(IDictionary<string, string> parameters, string charset)
{
StringBuilder postData = new StringBuilder();
bool hasParam = false;
IEnumerator<KeyValuePair<string, string>> dem = parameters.GetEnumerator();
while (dem.MoveNext())
{
string name = dem.Current.Key;
string value = dem.Current.Value;
// 忽略參數名或參數值為空的參數
if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))
{
if (hasParam)
{
postData.Append("&");
}
postData.Append(name);
postData.Append("=");
string encodedValue = HttpUtility.UrlEncode(value, Encoding.GetEncoding(charset));
postData.Append(encodedValue);
hasParam = true;
}
}
return postData.ToString();
}
/// <summary>
/// 組裝普通文本請求參數(不帶Encode)。
/// </summary>
/// <param name="parameters">Key-Value形式請求參數字典</param>
/// <returns>URL編碼后的請求數據</returns>
public static string BuildQueryWithOutEncode(IDictionary<string, string> parameters)
{
StringBuilder postData = new StringBuilder();
bool hasParam = false;
IEnumerator<KeyValuePair<string, string>> dem = parameters.GetEnumerator();
while (dem.MoveNext())
{
string name = dem.Current.Key;
string value = dem.Current.Value;
// 忽略參數名或參數值為空的參數
if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(value))
{
if (hasParam)
{
postData.Append("&");
}
postData.Append(name);
postData.Append("=");
string encodedValue = value;
postData.Append(encodedValue);
hasParam = true;
}
}
return postData.ToString();
}
/// <summary>
/// 配置(請自行填上下面兩個參數)
/// </summary>
public class Config
{
/// <summary>
/// 應用APPID
/// </summary>
public const string app_id = "";
/// <summary>
/// 私鑰,通過工具生成
/// </summary>
public const string privtekey = "";
}
服務端的完整代碼就如上了。
下面我吧HBuilder里面的代碼也寫一下,就是選擇好“支付寶”之后,執行的代碼是:
plus.nativeUI.showWaiting();
mui.post("http://wxpay.lmx.ren/AliPay/GetPayInfo", {
_amount: 0.01
}, function(data) {
plus.nativeUI.closeWaiting();
if (data) {
plus.payment.request(payChanel, data, function(result) {
console.log(JSON.stringify(result));
mui.alert(JSON.stringify(result), title);
mui.alert("付費成功", title);
}, function(e) {
console.log(JSON.stringify(e));
alert(JSON.stringify(e));
mui.alert("付費失敗", title);
});
} else {
plus.nativeUI.alert("支付失敗");
}
});
好了,就是如此簡單。下面貼幾張成功的圖片,方便大家預覽。



好了,這次教程到此結束。如果代碼有漏的,回復評論,我會上來看。如果需要討論的,加群討論,QQ個人好友已滿,加不了了,抱歉。
到這里,就大功告成啦,接下來的東西,就由大家自己去展開拓展了,本次經驗分享到此結束,寫過博客的人都知道,好好寫一個博客,需要自己從頭重新走一遍代碼,所以,各種辛苦,只有自己能體會。所以您如果覺得寫得不錯,或者對你有幫助,請點“
好文要頂
”或者“
關注我
”,順帶也可以評論一兩句,大家互相交流交流,
轉載請保留原作者地址以及姓名
。
我新建一個QQ群,如果有問題,可以在群里提。如果合適,也會根據大家提的比較多的問題,來寫篇博文,幫助更多的人,群號:275523437
點擊鏈接加入群【.Net,MVC,EasyUI,MUI,Html,JS】:
http://jq.qq.com/?_wv=1027&k=2A0RbLd
(如果有私活,或者一起合作的,也可以私信找我呀,嘿嘿);
作者:南宮蕭塵
E-mail:314791147@qq.com
QQ:314791147
日期:2017-01-05
需要實時測試的,可以關注公眾號,測試相關功能(根據實際情況,可能會不定時更新程序,如果需要最新程序的,可以加群聯系,QQ群號在上面):

【原創分享·微信支付】 C# MVC 微信支付教程系列之公眾號支付
【原創分享·微信支付】C# MVC 微信支付之微信模板消息推送
【原創分享·支付寶支付】HBuilder打包APP調用支付寶客戶端支付