因为支付宝已经集成了完整的SDK,所以可以使用SDK直接调用API,这里获取SDK源码。
首先我们需要引用支付宝SDK集成 AopSdk.dll,
添加相关引用:
using Aop.Api.Util;
需要用到商户私钥,支付宝公钥,请求地址等公共参数,所以可以新建一个config文件:
public class newalipayconfig { public newalipayconfig() { // // TODO: 在此处添加构造函数逻辑 // } // 应用ID,您的APPID public static string app_id = ""; // 支付宝网关 public static string gatewayUrl = "https://openapi.alipay.com/gateway.do"; // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。 public static string alipay_public_key = ""; // 商户私钥,您的原始格式RSA私钥 public static string private_key = ""; // 签名方式 public static string sign_type = "RSA2"; // 编码格式 public static string charset = "UTF-8"; }回调页面验签处理:
string subNumber; string total_fee; //获取总金额 protected void Page_Load(object sender, EventArgs e) { Dictionary<string, string> sArray = GetRequestPost(); if (sArray.Count != 0) { string trade_no = Request.Form["trade_no"];//获取返回状态 bool signVerified = AlipaySignature.RSACheckV1(sArray, newalipayconfig.alipay_public_key, newalipayconfig.charset, newalipayconfig.sign_type, false); //调用SDK验证签名 if (signVerified) { // TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure if (Request.Form["trade_status"] == "TRADE_FINISHED" || Request.Form["trade_status"] == "TRADE_SUCCESS")// 判断支付状态TRADE_FINISHED(文档中有枚举表可以参考) { subNumber = Request.Form["out_trade_no"];//商品订单号 total_fee = Request.Form["total_fee"]; Response.Write("success"); //返回给支付宝消息,成功 } else { Response.Write("fail"); } } else { // TODO 验签失败则记录异常日志,并在response中返回failure. Response.Write("fail"); } } } //获取所有参数,存入map中 public Dictionary<string, string> GetRequestPost() { int i = 0; Dictionary<string, string> sArray = new Dictionary<string, string>(); NameValueCollection coll; coll = Request.Form; String[] requestItem = coll.AllKeys; for (i = 0; i < requestItem.Length; i++) { sArray.Add(requestItem[i], Request.Form[requestItem[i]]); } return sArray; }
异步返回结果的验签
某商户设置的通知地址为https://api.xx.com/receive_notify.htm,对应接收到通知的示例如下:
https://api.xx.com/receive_notify.htm?total_amount=2.00&buyer_id=2088102116773037&body=大乐透2.1&trade_no=2016071921001003030200089909&refund_fee=0.00¬ify_time=2016-07-19 14:10:49&subject=大乐透2.1&sign_type=RSA2&charset=utf-8¬ify_type=trade_status_sync&out_trade_no=0719141034-6418&gmt_close=2016-07-19 14:10:46&gmt_payment=2016-07-19 14:10:47&trade_status=TRADE_SUCCESS&version=1.0&sign=kPbQIjX+xQc8F0/A6/AocELIjhhZnGbcBN6G4MM/HmfWL4ZiHM6fWl5NQhzXJusaklZ1LFuMo+lHQUELAYeugH8LYFvxnNajOvZhuxNFbN2LhF0l/KL8ANtj8oyPM4NN7Qft2kWJTDJUpQOzCzNnV9hDxh5AaT9FPqRS6ZKxnzM=&gmt_create=2016-07-19 14:10:44&app_id=2015102700040153&seller_id=2088102119685838¬ify_id=4a91b7a78a503640467525113fb7d8bg8e
第一步: 在通知返回参数列表中,除去sign、sign_type两个参数外,凡是通知返回回来的参数皆是待验签的参数。
第二步: 将剩下参数进行url_decode, 然后进行字典排序,组成字符串,得到待签名字符串:
body=大乐透2.1&buyer_id=2088102116773037&charset=utf-8&gmt_close=2016-07-19 14:10:46&gmt_payment=2016-07-19 14:10:47¬ify_time=2016-07-19 14:10:49¬ify_type=trade_status_sync&out_trade_no=0719141034-6418&refund_fee=0.00&subject=大乐透2.1&total_amount=2.00&trade_no=2016071921001003030200089909&trade_status=TRADE_SUCCESS&version=1.0
第三步: 将签名参数(sign)使用base64解码为字节码串。
第四步: 使用RSA的验签方法,通过签名字符串、签名参数(经过base64解码)及支付宝公钥验证签名。
第五步:需要严格按照如下描述校验通知数据的正确性。
SDK自带的验证签名方法,字典排序支持得.NET 3.5以上的版本,所以如果使用的是.NET 2.0版本的需要自己处理签名字符串:
protected void Page_Load(object sender, EventArgs e) { Dictionary<string, string> sArray = GetRequestPost(); if (sArray.Count != 0) { sArray.Remove("sign");//除去"sign"参数 sArray.Remove("sign_type");//除去"sign_type"参数 List<KeyValuePair<string, string>> lst = new List<KeyValuePair<string, string>>(sArray); //倒叙排列:只需要把变量s2 和 s1 互换就行了 例: return s1.Value.CompareTo(s2.Value); //进行排序 目前是顺序 lst.Sort(delegate(KeyValuePair<string, string> s1, KeyValuePair<string, string> s2) { return s2.Value.CompareTo(s1.Value); }); string signContent = string.Empty; string sign = Request.Form["sign"]; foreach (KeyValuePair<string, string> kvp in lst) { signContent += kvp.Key + "=" + kvp.Value + "&"; } signContent = signContent.ToString().Substring(0, signContent.Length - 1); string publicKeyPem = ""; string out_trade_no = Request.Form["out_trade_no"]; string trade_no = Request.Form["trade_no"]; //调用SDK验签方法 bool signVerified = AlipaySignature.RSACheckContent(signContent, sign, newalipayconfig.alipay_public_key, newalipayconfig.charset, newalipayconfig.sign_type, false); if (signVerified) //验证支付发过来的消息,签名是否正确 { Response.Write("success"); //返回给支付宝消息,成功 } else { v_success.Value = "0"; Response.Write(sign + "<br/"); } } } public Dictionary<string, string> GetRequestPost() { int i = 0; Dictionary<string, string> sArray = new Dictionary<string, string>(); NameValueCollection coll; //coll = Request.Form; coll = Request.Form; String[] requestItem = coll.AllKeys; for (i = 0; i < requestItem.Length; i++) { sArray.Add(requestItem[i], Request.Form[requestItem[i]]); } return sArray; }