博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
微信支付[v3]
阅读量:7239 次
发布时间:2019-06-29

本文共 16778 字,大约阅读时间需要 55 分钟。

V2升级V3 顺便记录一下 ,文档:

!!!

  • 支付授权目录与测试人的微信帐号白名单(出现access_denied或access_not_allow错误,请检查是否设置正确)
  • 微信签名(用于jssdk调用支付,查询订单,异步参数签名等)
  • 数字证书,用于微信退款

 

官方:

微信内网页支付时序图

参数签名

对所有传入参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL 键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1,注意:值为空的参数不参与签名 在string1 最后拼接上key=Key( 商户支付密钥) 得到stringSignTemp 字符串, 并对stringSignTemp 进行md5 运算,再将得到的字符串所有字符转换为大写,得到sign 值signValue

///         /// 创建微信Sign        ///         /// 微信商户支付密钥        /// 参数字典        /// 
public string GenerateWxSign(string key, SortedDictionary
dict) { try { string str = string.Empty; foreach (var item in dict) { if (item.Key != "sign" && item.Value.ToString() != "") { str += item.Key + "=" + item.Value + "&"; } } str = str.Trim('&'); //在string后加入API KEY str += "&key=" + key; //MD5加密 var md5 = System.Security.Cryptography.MD5.Create(); var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str)); var sb = new StringBuilder(); foreach (byte b in bs) { sb.Append(b.ToString("x2")); } //所有字符转为大写 return sb.ToString().ToUpper(); } catch (Exception) { return string.Empty; } }

异步通知

基本按照文档来,返回的参数要使用流的方式来读取XML,另外验证参数的合法性可以验证签名或调用一次微信订单查询接口

///     /// 微信支付异步回调控制器【V3版本】    ///     public class WeixinController : Controller    {        private static readonly Logger logger = LogManager.GetCurrentClassLogger();        ///         /// 订单服务        ///         private readonly IOrderService _orderService;        ///         /// 微信服务        ///         private readonly IWeixinService _weixinService;        ///         /// 构造函数        ///         /// 订单服务        /// 微信服务        public WeixinController(IOrderService orderService, IWeixinService weixinService)        {            _orderService = orderService;            _weixinService = weixinService;        }        ///         /// 微信Wap支付异步通知        ///         /// 
public async Task
Notify() { int intLen = Convert.ToInt32(Request.InputStream.Length); if (intLen <= 0) { return Content(AjaxResult.Error("WeixinController NO Wap Notify PARAMS!").ToStringSafe()); } try { var dict = new SortedDictionary
(); //dict = @"appid=wxqe353dd942e01&attach=F&bank_type=CFT&cash_fee=1&fee_type=CNY&is_subscribe=Y&mch_id=10036766&nonce_str=e9605038cccbffe5ed2b2eb095345d18&openid=oIO3gjsiGqv7eeuAKhbB_V83V528&out_trade_no=68047857&result_code=SUCCESS&return_code=SUCCESS&sign=85A469F874619EAB924FA5B7EB779444&time_end=20150526183632&total_fee=1&trade_type=JSAPI&transaction_id=1001640542201505260168707842".ConvertStringToSortedDictionary(); var xmlDoc = new XmlDocument(); xmlDoc.Load(Request.InputStream); var root = xmlDoc.SelectSingleNode("xml"); XmlNodeList xnl = root.ChildNodes; foreach (XmlNode xnf in xnl) { dict.Add(xnf.Name, xnf.InnerText); } if (dict.Count <= 0) { return Content(AjaxResult.Error("NO Notify PARAMS!").ToStringSafe()); } logger.Info("【 WeixinController Wap Notify SDKUtil.ConvertDictionaryToString : 请求报文=[" + dict.ConvertDictionaryToString() + "]\n"); //验证参数签名 string signK = _weixinService.GenerateWxSign(WxPayConfig.KEY, dict); if (signK != dict["sign"]) { logger.Info("WeixinController Wap Notify Verify WxSign Error : 请求报文=[signK " + signK + " : dict['sign'] " + dict["sign"] + "]\n"); return Content(AjaxResult.Error("WeixinController Wap Notify Verify WxSign Error " + "]\n").ToStringSafe()); } //验证通信标识 string return_code = dict["return_code"]; if (!return_code.Equals("SUCCESS", StringComparison.OrdinalIgnoreCase)) { string return_msg = dict["return_msg"]; logger.Info("WeixinController Wap Notify return_code Error : 请求报文=[" + return_code + " : " + return_msg + "]\n"); return Content(AjaxResult.Error("WeixinController Wap Notify return_code Error " + return_code + "]\n").ToStringSafe()); } //验证交易标识 string result_code = dict["result_code"]; if (!result_code.Equals("SUCCESS", StringComparison.OrdinalIgnoreCase)) { string err_code = dict["err_code"]; string err_code_des = dict["err_code_des"]; logger.Info("WeixinController Wap Notify return_code Error : 请求报文=[" + err_code + " : " + err_code_des + "]\n"); return Content(AjaxResult.Error("WeixinController Wap Notify return_code Error " + result_code + "]\n").ToStringSafe()); } //公众账号ID string appid = dict["appid"]; //商户号 string mch_id = dict["mch_id"]; //随机字符串 string nonce_str = dict["nonce_str"]; //签名 string sign = dict["sign"]; //用户在商户appid 下的唯一标识 string openid = dict["openid"]; //用户是否关注公众账 string is_subscribe = dict["is_subscribe"]; //交易类型 string trade_type = dict["trade_type"]; //付款银行 string bank_type = dict["bank_type"]; //订单总金额,单位为分 string total_fee = dict["total_fee"]; //金额分转元 string total_fee_rmb = (float.Parse(total_fee) / 100).ToString(); //商户订单号 string out_trade_no = dict["out_trade_no"]; //微信支付订单号 string transaction_id = dict["transaction_id"]; //商家数据包 string attach = dict["attach"]; //支付完成时间 string time_end = dict["time_end"]; //支付方式 string paymethod = attach; //微信订单查询【使用签名验证废弃】 //var wxorder = await _weixinService.Query(WxPayConfig.KEY, WxPayConfig.APPID, WxPayConfig.MCHID, transaction_id, out_trade_no); //检查订单是否已经支付 var order = await _orderService.Query(out_trade_no); if (order.IsNull() || order.Total_fee.IsNotNullOrEmpty()){ return Content(AjaxResult.Error("ORDERNO STATUS ERROR !!!").ToStringSafe()); } //更新支付金额与订单状态 var orderFlag = await _orderService.Update(crsResv); if (orderFlag.IsError) { logger.Fatal("WeixinController Wap Notify Update Order Error crsResv : " + crsResv.SerializeJson(System.Text.Encoding.UTF8)); return Json(new { IsError = true, Msg = "更新订单数据错误", Data = string.Empty }, JsonRequestBehavior.AllowGet); } //微信支付发货通知 var wxNotify = await _weixinService.WeixinNotify(openid, transaction_id, out_trade_no); //记录DB var save = await _weixinService.Save(wxAsync); //构造返回成功XML var wxdict = new SortedDictionary
(); wxdict.Add("return_code", "SUCCESS"); wxdict.Add("return_msg", "PAY_SUCCESS"); string wxRXml = wxdict.ConvertWxDictToString(); logger.Info("WeixinController Wap Notify Success wxRXml : " + wxRXml + " 】"); return Content(wxRXml); } catch (Exception ex) { logger.Fatal("WeixinController Wap Notify Exception : " + ex.Message + " 】", ex); return Content(AjaxResult.Error("WeixinController Wap Notify Exception").ToStringSafe()); } } ///
/// 字典转微信返回XML /// ///
///
///
///
public static string ConvertWxDictToString
(this IDictionary
wxdict) { try { string xml = "
"; wxdict.ForEach(wd => { if (wd.Value.GetType() == typeof(int)) { xml += "<" + wd.Key + ">" + wd.Value + "
"; } else if (wd.Value.GetType() == typeof(string)) { xml += "<" + wd.Key + ">" + "
"; } }); xml += "
"; return xml; } catch (Exception) { return string.Empty; } }

订单查询

///         /// 微信订单查询         ///         /// 公众账号ID        /// 商户号        /// 微信的订单号        /// 商户订单号        /// 随机字符串        /// 签名        /// 
public async Task
Query(string appid, string mch_id, string transaction_id, string out_trade_no, string nonce_str, string sign) { if (appid.IsEmpty() || mch_id.IsEmpty() || transaction_id.IsEmpty()) { return new WebAPIResponse { IsError = true, Msg = "参数有误!!!" }; } try { var dict = new Dictionary
(); dict.Add("appid", appid); dict.Add("mch_id", mch_id); dict.Add("transaction_id", transaction_id); dict.Add("out_trade_no", out_trade_no); dict.Add("nonce_str", nonce_str); dict.Add("sign", sign); string xml = "
"; foreach (var pair in dict) { if (pair.Value.GetType() == typeof(int)) { xml += "<" + pair.Key + ">" + pair.Value + "
"; } else if (pair.Value.GetType() == typeof(string)) { xml += "<" + pair.Key + ">" + "
"; } } xml += "
"; logger.Info("WeixinRepository WeixinNotify Req xml: " + xml); var data = await @"https://api.mch.weixin.qq.com/pay/orderquery".PostStringAsync(xml).ReceiveString(); logger.Info("WeixinRepository WeixinNotify Resp xml: " + data); if (data.IsNotNullOrEmpty() && data.Contains("SUCCESS", StringComparison.OrdinalIgnoreCase)) { return new WebAPIResponse { IsError = false, Data = "查询订单成功!!!" }; } return new WebAPIResponse { IsError = true, Msg = "微信订单查询失败!!!" }; } catch (Exception ex) { logger.Error("WeixinRepository WeixinNotify ConvertDictionaryToJson Exception :" + ex.Message, ex); return new WebAPIResponse { IsError = true, Msg = ex.Message }; } }

微信退款

!!!需注意签名与证书

///         /// 微信申请退款V3        ///         /// 订单号        /// 
public bool RefundWxV3(string orderNo) { try { //查询支付信息 var orderAsync =await _orderService.Query(orderNo); var dict = new SortedDictionary
(); dict.Add("appid", WxPayConfig.APPID); dict.Add("mch_id", WxPayConfig.MCHID); dict.Add("nonce_str", ConstantKey.NonceStr); dict.Add("transaction_id", orderAsync.transaction_id); dict.Add("out_trade_no", orderAsync.out_trade_no); dict.Add("out_refund_no", WxPayConfig.GenerateOutTradeNo); dict.Add("total_fee", orderAsync.total_fee); dict.Add("refund_fee", orderAsync.total_fee); dict.Add("op_user_id", WxPayConfig.MCHID); string sign = GenerateWxSign(WxPayConfig.KEY, dict); dict.Add("sign", sign); string xml = "
"; foreach (var pair in dict) { if (pair.Value.GetType() == typeof(int)) { xml += "<" + pair.Key + ">" + pair.Value + "
"; } else if (pair.Value.GetType() == typeof(string)) { xml += "<" + pair.Key + ">" + "
"; } } xml += "
"; logger.Info("RefundWxV3 Req xml: " + xml); var data = HttpWxCert(@"https://api.mch.weixin.qq.com/secapi/pay/refund", "POST", xml, "text/xml", isUseCert: true); logger.Info("RefundWxV3 Resp xml: " + data); if (data.IsNotEmpty() && data.Contains("SUCCESS", StringComparison.OrdinalIgnoreCase)) { return true; } return false; } catch (Exception ex) { logger.Error("CancelResvForWeb RefundWxV3 Exception :" + ex.Message, ex); return false; } } ///
/// 创建HTTP请求 /// ///
请求URL ///
请求方式 ///
请求参数 ///
设置HTTP contentType类型 ///
是否使用证书 ///
请求超时时间 ///
public static string HttpWxCert(string url, string method = "GET", string data = null, string contentType = "application/x-www-form-urlencoded", bool isUseCert = false, int timeout = 15000) { if (url.IsEmpty()) throw new ArgumentNullException("url"); HttpWebRequest req = null; HttpWebResponse resp = null; StreamReader sr = null; Stream stream = null; try { if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase)) { System.Net.ServicePointManager.ServerCertificateValidationCallback += (se, cert, chain, sslError) => { return true; }; } //设置最大连接数 System.Net.ServicePointManager.DefaultConnectionLimit = 200; req = (HttpWebRequest)WebRequest.Create(url); req.Method = method.ToUpper(); req.Timeout = timeout; req.ContentType = contentType; //是否使用证书 if (isUseCert) { string pfxPath = WxPayConfig.SSLCERT_PATH; logger.Info("wxV3.signCert.path pfxPath : " + pfxPath + " File Exists: " + File.Exists(pfxPath)); //string path = HttpContext.Current.Request.PhysicalApplicationPath; //调用证书 var cert = new X509Certificate2(pfxPath, WxPayConfig.SSLCERT_PASSWORD, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet); req.ClientCertificates.Add(cert); } if (method.ToUpper() == "POST" && !data.IsEmpty()) { byte[] postBytes = UTF8Encoding.UTF8.GetBytes(data); req.ContentLength = postBytes.Length; using (stream = req.GetRequestStream()) { stream.Write(postBytes, 0, postBytes.Length); } } resp = (HttpWebResponse)req.GetResponse(); using (sr = new StreamReader(resp.GetResponseStream(), Encoding.UTF8)) { return sr.ReadToEnd().Trim(); } } catch (Exception ex) { logger.Error(string.Format("HttpWxCert Exception url: {0} \r\n data: {1}", url, data), ex); return string.Empty; } finally { if (sr != null) { sr.Close(); sr = null; } if (stream != null) { stream.Close(); stream = null; } if (resp != null) { resp.Close(); resp = null; } if (req != null) { req.Abort(); req = null; } } }

Refer:

微信支付接口退款时:System.Security.Cryptography.CryptographicException

转载地址:http://mtrfm.baihongyu.com/

你可能感兴趣的文章
《刻意练习》读后感
查看>>
DataWorks V2.0 系列公开课
查看>>
使用 logstash, elasticsearch, kibana 搭建日志分析系统
查看>>
Android Q 将获得大量的隐私保护功能
查看>>
《恋恋笔记本》观后感
查看>>
Spring源码剖析6:Spring AOP概述
查看>>
Maven的POM.xml配置大全
查看>>
SmartRefreshLayout + BaseRecyclerviewAdapterHelper 使用MVP方式实现下拉刷新
查看>>
详解KVC(转载)
查看>>
tp5 发送阿里云短信
查看>>
cookie java spring
查看>>
Thrift之TProcess类体系原理及源码详细解析
查看>>
python写的一段分页的代码
查看>>
阿里巴巴数学大赛赛题公布,你敢来挑战吗?(含参考答案)
查看>>
设计模式六大原则(1):单一职责原则
查看>>
ubnutu日常使用软件
查看>>
keras 迁移学习inception_v3,缺陷检测
查看>>
【Java】多线程简单了解
查看>>
彩铅练习:蓝色花朵
查看>>
Shell脚本的一些小技巧
查看>>