C# 微信支付V3支付回调验签处理

微信支付完成后会有一个支付回调页面,处理支付完成后的事件,V3支付回调的数据形式为XML格式。

1、定义一个WxResponseHandlerV3类,处理一般构造函数,用于解析XML对象;

//xmlMap
private Hashtable xmlMap;
//解析回传参数,将带有指定键和值的元素添加到 System.Collections.Hashtable 中。
        public WxResponseHandlerV3(HttpContext _httpContext)
        {
            xmlMap = new Hashtable();
            this.httpContext = _httpContext;

            Stream stream = this.httpContext.Request.InputStream;
            if (stream.Length > 0)
            {
                XmlDocument xmlDoc = new XmlDocument();
                StreamReader sr = new StreamReader(stream, System.Text.Encoding.UTF8);
                string strInputStream = sr.ReadToEnd();
                Tools.PublicConfig.log_Append("stream length:" + stream.Length.ToString()
                    + "this.httpContext.Request.InputStream string: " + strInputStream, "Pay/Pay_WxV3", DateTime.Now.ToString("yyyyMMdd") + ".log");
                xmlDoc.LoadXml(strInputStream);
                XmlNode root = xmlDoc.SelectSingleNode("xml");
                XmlNodeList xnl = root.ChildNodes;

                foreach (XmlNode xnf in xnl)
                {
                    xmlMap.Add(xnf.Name, xnf.InnerText);
                }
            }
            if (stream != null)
            {
                stream.Close();
            }
        }

2、验签处理

 /** V3支付返回notify签名:按参数名称a-z排序,遇到空值的参数不参加签名。  //全部是 xmlMap 参数
       * @return boolean */
        public virtual Boolean isNotifySign()
        {
            StringBuilder sb = new StringBuilder();

            ArrayList akeys = new ArrayList(xmlMap.Keys);
            akeys.Sort();

            foreach (string k in akeys)
            {
                string v = (string)getXmlMap(k);
                if (null != v && "".CompareTo(v) != 0
                    && "sign".CompareTo(k) != 0 && "key".CompareTo(k) != 0)
                {
                    sb.Append(k + "=" + v + "&");
                }
            }

            sb.Append("key=" + this.getPayKey());
            string sign = Wxpay.MD5Util.MD5(sb.ToString()).ToUpper();
            //debug信息
            return getXmlMap("sign").ToUpper().Equals(sign);
        }

/** 获取xmlMap值 */
        public string getXmlMap(string parameter)
        {
            string s = (string)xmlMap[parameter];
            return (null == s) ? "" : s;
        }

/// <summary>
        /// 设置V3 支付密钥
        /// </summary>
        /// <param name="key"></param>
        public void setPayKey(string key)
        {
            this.paykey = key;
        }
        /** 获取V3支付密钥 */
        public string getPayKey()
        { return this.paykey; }

MD5加密方法

/// <summary>
        /// 获得MD5加密字符串
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <returns>目标字符串</returns>
        public static String MD5(String s)
        {
            char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
            try
            {
                byte[] btInput = System.Text.Encoding.UTF8.GetBytes(s);
                // 获得MD5摘要算法的 MessageDigest 对象
                MD5 mdInst = System.Security.Cryptography.MD5.Create();
                // 使用指定的字节更新摘要
                mdInst.ComputeHash(btInput);
                // 获得密文
                byte[] md = mdInst.Hash;
                // 把密文转换成十六进制的字符串形式
                int j = md.Length;
                char[] str = new char[j * 2];
                int k = 0;
                for (int i = 0; i < j; i++)
                {
                    byte byte0 = md[i];
                    str[k++] = hexDigits[(int)(((byte)byte0) >> 4) & 0xf];
                    str[k++] = hexDigits[byte0 & 0xf];
                }
                return new string(str);
            }
            catch
            {
                // Console.Error.WriteLine(e.StackTrace);
                return null;
            }
        }


3、添加回调页面

public ActionResult WxApplyPayNotify()
        {
            Response.ContentType = "text/xml";
            Response.ContentEncoding = System.Text.Encoding.UTF8;
            Response.CacheControl = "no-cache";
            bool MyBusiness = false;
            try
            {
                if (Request.InputStream.Length > 0)
                {
                    Wxpay.WxResponseHandlerV3 res = new Wxpay.WxResponseHandlerV3(System.Web.HttpContext.Current);
                    res.setPayKey("sdjhfksdjhfksdjfhkkjhsdkfjh");//支付秘钥
                    bool notifySign = res.isNotifySign();//验签
                    if (notifySign)
                    {
                        //分期支付的out_trade_no是分期订单支付请求的requestNo
                        string requestNo = res.getXmlMap("out_trade_no");
                        //财付通订单号
                        String transaction_id = res.getXmlMap("transaction_id");
                        //金额,以分为单位
                        String total_fee = res.getXmlMap("total_fee");
                        // 是否关注公众账号is_subscribe 是String(1) 用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效
                        string is_subscribe = res.getXmlMap("is_subscribe");
                        
                        //判断签名及结果
                        if ("SUCCESS".Equals(result_code.ToUpper()))
                        {
                            //支付成功,处理其他事物。。。

                        }
                        else
                        {
                            //支付失败处理。。。
                            MyBusiness = true;
                        }

                        if (MyBusiness)
                        {
                            Response.Write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
                        }
                        else
                        {
                            Response.Write("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[My Business error]]></return_msg></xml>");
                        }

                    }
                    else
                    {
                        Response.Write("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名验证失败]]></return_msg></xml>");
                    }
                }

            }
            catch (Exception ex)
            {

                //系统异常
            }
            return View();
        }

猜你喜欢

转载自blog.csdn.net/lwpoor123/article/details/79866632