[转载]微信支付

公众号支付有2种支付方式:

JS API 支付:是指用户打开图文消息或者扫描二维码,在微信内置浏览器打开网页进行的支付。商户网页前端通过使用微信提供的 JS API,调用微信支付模块。这种方式,适合
需要在商户网页进行选购下单的购买流程。
Native(原生)支付:是指商户组成符合 Native(原生)支付规则的 URL 链接,用户可通过点击该链接或者扫描对应的二维码直接进入微信支付模块(微信客户端界面),即可
进行支付。这种方式,适合无需选购直接支付的购买流程。

以上两种方式最大的区别是:是否需要经过网页调用!

交互原理:

客户是想做一个手机端的商城,所以选择JS API支付,通过网页调取微信支付。。

楼主第一次看过文档后,什么“支付签名(paySign)”啊,什么“package包”啊等等一些参数,反正似懂非懂的样子。楼主这人比较懒,不然也不 会注册3年了,也就写了这么篇不入流的文章,楼主想啊像这些个大公司开放个啥接口的肯定会有demo。楼主的运气还真不错(PS:楼主可是为福利事业贡献 了不少哦,咋就没这运气?),还真让楼主找到了,那心情肯定是比不上中500W的,嘿嘿。

<!DOCTYPE html>
<html>
    <head>
        <title>公众号支付测试网页</title>
        <script language="javascript" src="http://res.mail.qq.com/mmr/static/lib/js/jquery.js"></script>
        <script language="javascript" src="http://res.mail.qq.com/mmr/static/lib/js/lazyloadv3.js"></script>
        <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js"></script>
        <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha1.js"></script>
        <script Language="javascript">
            //辅助函数
            function Trim(str,is_global)
            {
                var result;
                result = str.replace(/(^\s+)|(\s+$)/g,"");
                if(is_global.toLowerCase()=="g") result = result.replace(/\s/g,"");
                return result;
            }
            function clearBr(key)
            {
                key = Trim(key,"g");
                key = key.replace(/<\/?.+?>/g,"");
                key = key.replace(/[\r\n]/g, "");
                return key;
            }

            //获取随机数
            function getANumber()
            {
                var date = new Date();
                var times1970 = date.getTime();
                var times = date.getDate() + "" + date.getHours() + "" + date.getMinutes() + "" + date.getSeconds();
                var encrypt = times * times1970;
                if(arguments.length == 1){
                    return arguments[0] + encrypt;
                }else{
                    return encrypt;
                }

            }

            //以下是package组包过程:

            var oldPackageString;//记住package,方便最后进行整体签名时取用

            function getPartnerId()
            {
                return document.form1.partnerId.value;
            }

            function getPartnerKey()
            {
                return "8934e7d15453e97507ef794cf7b0519d";
            }

            function getPackage()
            {
                var banktype = "WX";
                var body = document.form1.body.value;//商品名称信息,这里由测试网页填入。
                var fee_type = "1";//费用类型,这里1为默认的人民币
                var input_charset = "GBK";//字符集,这里将统一使用GBK
                var notify_url = "http://www.qq.com";//支付成功后将通知该地址
                var out_trade_no = ""+getANumber();//订单号,商户需要保证该字段对于本商户的唯一性
                var partner = getPartnerId();//测试商户号
                var spbill_create_ip = "127.0.0.1";//用户浏览器的ip,这个需要在前端获取。这里使用127.0.0.1测试值
                var total_fee = document.form1.totalFee.value;//总金额。
                var partnerKey = getPartnerKey();//这个值和以上其他值不一样是:签名需要它,而最后组成的传输字符串不能含有它。这个key是需要商户好好保存的。

                //首先第一步:对原串进行签名,注意这里不要对任何字段进行编码。这里是将参数按照key=value进行字典排序后组成下面的字符串,在这个字符串最后拼接上key=XXXX。由于这里的字段固定,因此只需要按照这个顺序进行排序即可。
                var signString = "bank_type="+banktype+"&body="+body+"&fee_type="+fee_type+"&input_charset="+input_charset+"&notify_url="+notify_url+"&out_trade_no="+out_trade_no+"&partner="+partner+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+total_fee+"&key="+partnerKey;

                var md5SignValue =  ("" + CryptoJS.MD5(signString)).toUpperCase();
                //然后第二步,对每个参数进行url转码,如果您的程序是用js,那么需要使用encodeURIComponent函数进行编码。

                banktype = encodeURIComponent(banktype);
                body=encodeURIComponent(body);
                fee_type=encodeURIComponent(fee_type);
                input_charset = encodeURIComponent(input_charset);
                notify_url = encodeURIComponent(notify_url);
                out_trade_no = encodeURIComponent(out_trade_no);
                partner = encodeURIComponent(partner);
                spbill_create_ip = encodeURIComponent(spbill_create_ip);
                total_fee = encodeURIComponent(total_fee);

                //然后进行最后一步,这里按照key=value除了sign外进行字典序排序后组成下列的字符串,最后再串接sign=value
                var completeString = "bank_type="+banktype+"&body="+body+"&fee_type="+fee_type+"&input_charset="+input_charset+"&notify_url="+notify_url+"&out_trade_no="+out_trade_no+"&partner="+partner+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+total_fee;
                completeString = completeString + "&sign="+md5SignValue;

                oldPackageString = completeString;//记住package,方便最后进行整体签名时取用

                return completeString;
            }

            //下面是app进行签名的操作:

            var oldTimeStamp ;//记住timestamp,避免签名时的timestamp与传入的timestamp时不一致
            var oldNonceStr ; //记住nonceStr,避免签名时的nonceStr与传入的nonceStr不一致

            function getAppId()
            {
                return document.form1.appId.value;
            }

            function getAppKey()
            {
                return "2Wozy2aksie1puXUBpWD8oZxiD1DfQuEaiC7KcRATv1Ino3mdopKaPGQQ7TtkNySuAmCaDCrw4xhPY5qKTBl7Fzm0RgR3c0WaVYIXZARsxzHV2x7iwPPzOz94dnwPWSn";
            }

            function getTimeStamp()
            {
                var timestamp=new Date().getTime();
                var timestampstring = timestamp.toString();//一定要转换字符串
                oldTimeStamp = timestampstring;
                return timestampstring;
            }

            function getNonceStr()
            {
                var $chars = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789‘;
                var maxPos = $chars.length;
                var noceStr = "";
                for (i = 0; i < 32; i++) {
                    noceStr += $chars.charAt(Math.floor(Math.random() * maxPos));
                }
                oldNonceStr = noceStr;
                return noceStr;
            }

            function getSignType()
            {
                return "SHA1";
            }

            function getSign()
            {
                var app_id = getAppId().toString();
                var app_key = getAppKey().toString();
                var nonce_str = oldNonceStr;
                var package_string = oldPackageString;
                var time_stamp = oldTimeStamp;
                //第一步,对所有需要传入的参数加上appkey作一次key=value字典序的排序
                var keyvaluestring = "appid="+app_id+"&appkey="+app_key+"&noncestr="+nonce_str+"&package="+package_string+"&timestamp="+time_stamp;
                sign = CryptoJS.SHA1(keyvaluestring).toString();
                return sign;
            }

            </script>
        <meta http-equiv="content-type" content="text/html;charset=utf-8"/>
        <meta id="viewport" name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1; user-scalable=no;" />

        <style>

            body { margin:0;padding:0;background:#eae9e6; }
            body,p,table,td,th { font-size:14px;font-family:helvetica,Arial,Tahoma; }
            h1 { font-family:Baskerville,HelveticaNeue-Bold,helvetica,Arial,Tahoma; }
            a { text-decoration:none;color:#385487;}

            .container {  }
            .title { }
            #content {padding:30px 20px 20px;color:#111;box-shadow:0 1px 4px #ccc; background:#f7f2ed;  }
            .seeAlso { padding:15px 20px 30px; }

            .headpic div { margin:20px 0 0;}
            .headpic img { display:block;}

            .title h1 { font-size:22px;font-weight:bold;padding:0;margin:0;line-height:1.2;color:#1f1f1f; }
            .title p { color:#aaa;font-size:12px;margin:5px 0 0;padding:0;font-weight:bold;}
            .pic { margin:20px 0; }
            .articlecontent img { display:block;clear:both;box-shadow:0px 1px 3px #999; margin:5px auto;}
            .articlecontent p { text-indent: 2em; font-family:Georgia,helvetica,Arial,Tahoma;line-height:1.4; font-size:16px; margin:20px 0;  }

            .seeAlso h3 { font-size:16px;color:#a5a5a5;}
            .seeAlso ul { margin:0;padding:0; }
            .seeAlso li {  font-size:16px;list-style-type:none;border-top:1px solid #ccc;padding:2px 0;}
            .seeAlso li a { border-bottom:none;display:block;line-height:1.1; padding:13px 0; }

            .clr{ clear:both;height:1px;overflow:hidden;}

            .fontSize1 .title h1 { font-size:20px; }
            .fontSize1 .articlecontent p {  font-size:14px; }
            .fontSize1 .weibo .nickname,.fontSize1 .weibo .comment  { font-size:11px; }
            .fontSize1 .moreOperator { font-size:14px; }

            .fontSize2 .title h1 { font-size:22px; }
            .fontSize2 .articlecontent p {  font-size:16px; }
            .fontSize2 .weibo .nickname,.fontSize2 .weibo .comment  { font-size:13px; }
            .fontSize2 .moreOperator { font-size:16px; }

            .fontSize3 .title h1 { font-size:24px; }
            .fontSize3 .articlecontent p {  font-size:18px; }
            .fontSize3 .weibo .nickname,.fontSize3 .weibo .comment  { font-size:15px; }
            .fontSize3 .moreOperator { font-size:18px; }

            .fontSize4 .title h1 { font-size:26px; }
            .fontSize4 .articlecontent p {  font-size:20px; }
            .fontSize4 .weibo .nickname,.fontSize4 .weibo .comment  { font-size:16px; }
            .fontSize4 .moreOperator { font-size:20px; }

            .jumptoorg { display:block;margin:16px 0 16px; }
            .jumptoorg a {  }

            .moreOperator a { color:#385487; }

            .moreOperator .share{ border-top:1px solid #ddd; }

            .moreOperator .share a{ display:block;border:1px solid #ccc;border-radius:4px;margin:20px 0;border-bottom-style:solid;background:#f8f7f1;color:#000; }

            .moreOperator .share a span{ display:block;padding:10px 10px;border-radius:4px;text-align:center;border-top:1px solid #eee;border-bottom:1px solid #eae9e3;font-weight:bold; }

            .moreOperator .share a:hover,
            .moreOperator .share a:active { background:#efedea; }
            @media only screen and (-webkit-min-device-pixel-ratio: 2) {
            }
            </style>
        <script language="javascript">
            function auto_remove(img){
                div=img.parentNode.parentNode;div.parentNode.removeChild(div);
                img.onerror="";
                return true;
            }

            function changefont(fontsize){
                if(fontsize < 1 || fontsize > 4)return;
                $(‘#content‘).removeClass().addClass(‘fontSize‘ + fontsize);
            }

            // 当微信内置浏览器完成内部初始化后会触发WeixinJSBridgeReady事件。
            document.addEventListener(‘WeixinJSBridgeReady‘, function onBridgeReady() {
                                      //公众号支付
                                      jQuery(‘a#getBrandWCPayRequest‘).click(function(e){
                                                                             WeixinJSBridge.invoke(‘getBrandWCPayRequest‘,{
                                                                                                   "appId" : getAppId(), //公众号名称,由商户传入
                                                                                                   "timeStamp" : getTimeStamp(), //时间戳
                                                                                                   "nonceStr" : getNonceStr(), //随机串
                                                                                                   "package" : getPackage(),//扩展包
                                                                                                   "signType" : getSignType(), //微信签名方式:1.sha1
                                                                                                   "paySign" : getSign() //微信签名
                                                                                                   },function(res){
                                                                                                   if(res.err_msg == "get_brand_wcpay_request:ok" ) {}
                                                                                                   // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
                                                                                                   //因此微信团队建议,当收到ok返回时,向商户后台询问是否收到交易成功的通知,若收到通知,前端展示交易成功的界面;若此时未收到通知,商户后台主动调用查询订单接口,查询订单的当前状态,并反馈给前端展示相应的界面。
                                                                                                   }); 

                                                                             });

                                      WeixinJSBridge.log(‘yo~ ready.‘);

                                      }, false)

            if(jQuery){
                jQuery(function(){

                       var width = jQuery(‘body‘).width() * 0.87;
                       jQuery(‘img‘).error(function(){
                                           var self = jQuery(this);
                                           var org = self.attr(‘data-original1‘);
                                           self.attr("src", org);
                                           self.error(function(){
                                                      auto_remove(this);
                                                      });
                                           });
                       jQuery(‘img‘).each(function(){
                                          var self = jQuery(this);
                                          var w = self.css(‘width‘);
                                          var h = self.css(‘height‘);
                                          w = w.replace(‘px‘, ‘‘);
                                          h = h.replace(‘px‘, ‘‘);
                                          if(w <= width){
                                          return;
                                          }
                                          var new_w = width;
                                          var new_h = Math.round(h * width / w);
                                          self.css({‘width‘ : new_w + ‘px‘, ‘height‘ : new_h + ‘px‘});
                                          self.parents(‘div.pic‘).css({‘width‘ : new_w + ‘px‘, ‘height‘ : new_h + ‘px‘});
                                          });
                       });
            }
            </script>
    </head>
    <body>

        <form name="form1" target="_blank">
            <table border="1">
                <TR><th>公众号ID</th> <th><INPUT value="wxf8b4f85f3a794e77" name="appId" id="1"></th>
                    <tr><th>商户ID</th><th><INPUT value="1900000109" name="partnerId" id="2"></th>
                        <TR><th>总金额</th><th><INPUT value=1 name="totalFee" id="3"></th>
                            <TR><th>商品名</th><th><INPUT value="江诗丹顿" name="body" id="4"></th>
            </table>
        </form>
        <div class="WCPay">
            <a id="getBrandWCPayRequest" href="javascript:void(0);"><h1 class="title">提交</h1></a>
        </div>

    </body>
</html>

打开一看(楼主心里想TX你是多缺美工!),“提交”两字这么大,点一下试试,没反应?这不科学啊!立马找原因,当看到这句:“微信支付,是基于微信客户端提供的支付服务功能” ,楼主**(已和谐)了!放网站上用微信打开,这次有反应了!微信友情的提示我:“功能未授权”。。 这次知道是啥原因了,找客户沟通,原来合同快递还没到,保证金5W没交(现在只要2W了)。。

N天之后。。。。

这下测试能成功了,该怎么跟网站结合呢?不会直接把参数改了,然后让客户点提交吧?楼主想想这用户体验也太差了吧,客户肯定不认同。这问题纠结了楼主几 天,百撕不得骑姐。有一天突然企业QQ一个讨论组的图标老闪,我就纳闷我没加过讨论组啊,打开正想喷(实际也真没喷过,能拉进讨论组都是好友,不过问题解 不出来的时候确实很烦)的时候,人物列表那个头像怎么那么熟呢?那不我客户吗?瞬间一盆凉水从头到脚彻底没脾气了!A(TX商务人员):“你们的微信支付 做好了没?”,我:“还没呢。”,A:”有什么困难吗?”,我:“有,有一些地方不明白。”,A:”我帮你安排个技术支持吧?”,楼主欣喜若狂啊,从看到 这行信息到打出“好的”发出去绝对是没有超过1秒。。

之后楼主一帆风顺了,如鱼得水了,同事妹纸也变的水灵多了。。

<——————————————————————-吐 槽结束,华丽的分割线 —————————————————————–>

以下是.NET版本的微信支付:

MD5Util类:

using System;
using System.Security.Cryptography;
using System.Text;

namespace tenpayApp
{
    /// <summary>
    /// MD5Util 的摘要说明。
    /// </summary>
    public class MD5Util
    {
        public MD5Util()
        {
            //
            // TODO: 在此处添加构造函数逻辑
            //
        }

        /** 获取大写的MD5签名结果 */
        public static string GetMD5(string encypStr, string charset)
        {
            string retStr;
            MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider();

            //创建md5对象
            byte[] inputBye;
            byte[] outputBye;

            //使用GB2312编码方式把字符串转化为字节数组.
            try
            {
                inputBye = Encoding.GetEncoding(charset).GetBytes(encypStr);
            }
            catch (Exception ex)
            {
                inputBye = Encoding.GetEncoding("GB2312").GetBytes(encypStr);
            }
            outputBye = m5.ComputeHash(inputBye);

            retStr = System.BitConverter.ToString(outputBye);
            retStr = retStr.Replace("-", "").ToUpper();
            return retStr;
        }
    }
}

RequestHandler类:

using System;
using System.Collections;
using System.Text;
using System.Web;
using System.Xml;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace tenpayApp
{
    /**
    ‘签名工具类
     ============================================================================/// <summary>
    ‘api说明:
    ‘init();
    ‘初始化函数,默认给一些参数赋值。
    ‘setKey(key_)‘设置商户密钥
    ‘createMd5Sign(signParams);字典生成Md5签名
    ‘genPackage(packageParams);获取package包
    ‘createSHA1Sign(signParams);创建签名SHA1
    ‘parseXML();输出xml
    ‘getDebugInfo(),获取debug信息
     *
     * ============================================================================
     */
    public class RequestHandler
    {

        public RequestHandler(HttpContext httpContext)
        {
            parameters = new Hashtable();

            this.httpContext = httpContext;

        }
        /**  密钥 */
        private string key;

        protected HttpContext httpContext;

        /** 请求的参数 */
        protected Hashtable parameters;

        /** debug信息 */
        private string debugInfo;

        /** 初始化函数 */
        public virtual void init()
        {
        }
        /** 获取debug信息 */
        public String getDebugInfo()
        {
            return debugInfo;
        }
        /** 获取密钥 */
        public String getKey()
        {
            return key;
        }

        /** 设置密钥 */
        public void setKey(string key)
        {
            this.key = key;
        }

        /** 设置参数值 */
        public void setParameter(string parameter, string parameterValue)
        {
            if (parameter != null && parameter != "")
            {
                if (parameters.Contains(parameter))
                {
                    parameters.Remove(parameter);
                }

                parameters.Add(parameter, parameterValue);
            }
        }

        //获取package带参数的签名包
        public string getRequestURL()
        {
            this.createSign();
            StringBuilder sb = new StringBuilder();
            ArrayList akeys=new ArrayList(parameters.Keys);
            akeys.Sort();
            foreach(string k in akeys)
            {
                string v = (string)parameters[k];
                if(null != v && "key".CompareTo(k) != 0)
                {
                    sb.Append(k + "=" + TenpayUtil.UrlEncode(v, getCharset()) + "&");
                }
            }

            //去掉最后一个&
            if(sb.Length > 0)
            {
                sb.Remove(sb.Length-1, 1);
            }

           return sb.ToString();

        }

        //创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。

        protected virtual void  createSign()
        {
            StringBuilder sb = new StringBuilder();

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

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

            sb.Append("key=" + this.getKey());
            string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToUpper();

            this.setParameter("sign", sign);

            //debug信息
            this.setDebugInfo(sb.ToString() + " => sign:" + sign);
        }

       //创建package签名
        public virtual string createMd5Sign()
        {
            StringBuilder sb = new StringBuilder();
            ArrayList akeys=new ArrayList(parameters.Keys);
            akeys.Sort();

            foreach(string k in akeys)
            {
                string v = (string)parameters[k];
                if(null != v && "".CompareTo(v) != 0
                    && "sign".CompareTo(k) != 0 && "".CompareTo(v) != 0)
                {
                    sb.Append(k + "=" + v + "&");
                }
            }
            string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToLower();

            this.setParameter("sign", sign);
            return sign;
    }

        //创建sha1签名
        public string createSHA1Sign()
        {
            StringBuilder sb = new StringBuilder();
            ArrayList akeys = new ArrayList(parameters.Keys);
            akeys.Sort();

            foreach (string k in akeys)
            {
                string v = (string)parameters[k];
              if (null != v && "".CompareTo(v) != 0
                     && "sign".CompareTo(k) != 0 && "key".CompareTo(k) != 0)
                {
                    if(sb.Length==0)
                    {
                    sb.Append(k + "=" + v);
                    }
                    else{
                     sb.Append("&" + k + "=" + v);
                    }
                }
            }
            string paySign = SHA1Util.getSha1(sb.ToString()).ToString().ToLower();

            //debug信息
            this.setDebugInfo(sb.ToString() + " => sign:" + paySign);
            return paySign;
        }

         //输出XML
        public string parseXML()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<xml>");
            foreach (string k in parameters.Keys)
            {
                string v = (string)parameters[k];
                if (Regex.IsMatch(v, @"^[0-9.]$"))
                {

                    sb.Append("<" + k + ">" + v + "</" + k + ">");
                }
                else
                {
                    sb.Append("<" + k + "><![CDATA[" + v + "]]></" + k + ">");
                }

           }
            sb.Append("</xml>");
            return sb.ToString();
        }

        /** 设置debug信息 */
        public void setDebugInfo(String debugInfo)
        {
            this.debugInfo = debugInfo;
        }

        public Hashtable getAllParameters()
        {
            return this.parameters;
        }

         protected virtual string getCharset()
      {
          return this.httpContext.Request.ContentEncoding.BodyName;
      }
    }
}

ResponseHandler类:

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Text;
using System.Web;
using System.Xml;

namespace tenpayApp
{

    /**
    ‘============================================================================
    ‘api说明:
    ‘getKey()/setKey(),获取/设置密钥
    ‘getParameter()/setParameter(),获取/设置参数值
    ‘getAllParameters(),获取所有参数
    ‘isTenpaySign(),是否正确的签名,true:是 false:否
    ‘isWXsign(),是否正确的签名,true:是 false:否
    ‘ * isWXsignfeedback判断微信维权签名
    ‘ *getDebugInfo(),获取debug信息
    ‘============================================================================
    */

    public class ResponseHandler
    {
        // 密钥
        private string key;

        // appkey
        private string appkey;

        //xmlMap
        private Hashtable xmlMap;

        // 应答的参数
        protected Hashtable parameters;

         //debug信息
        private string debugInfo;
        //原始内容
        protected string content;

        private string charset = "gb2312";

        //参与签名的参数列表
        private static string SignField = "appid,appkey,timestamp,openid,noncestr,issubscribe";

        protected HttpContext httpContext;

        //初始化函数
        public virtual void init()
        {
        }

        //获取页面提交的get和post参数
        public ResponseHandler(HttpContext httpContext)
        {
            parameters = new Hashtable();
            xmlMap = new Hashtable();

            this.httpContext = httpContext;
            NameValueCollection collection;
            //post data
            if (this.httpContext.Request.HttpMethod == "POST")
            {
                collection = this.httpContext.Request.Form;
                foreach (string k in collection)
                {
                    string v = (string)collection[k];
                    this.setParameter(k, v);
                }
            }
            //query string
            collection = this.httpContext.Request.QueryString;
            foreach (string k in collection)
            {
                string v = (string)collection[k];
                this.setParameter(k, v);
            }
            if (this.httpContext.Request.InputStream.Length > 0)
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(this.httpContext.Request.InputStream);
                XmlNode root = xmlDoc.SelectSingleNode("xml");
                XmlNodeList xnl = root.ChildNodes;

                foreach (XmlNode xnf in xnl)
                {
                    xmlMap.Add(xnf.Name, xnf.InnerText);
                }
            }
        }

        /** 获取密钥 */
        public string getKey()
        { return key;}

        /** 设置密钥 */
        public void setKey(string key, string appkey)
        {
            this.key = key;
            this.appkey = appkey;
        }

        /** 获取参数值 */
        public string getParameter(string parameter)
        {
            string s = (string)parameters[parameter];
            return (null == s) ? "" : s;
        }

        /** 设置参数值 */
        public void setParameter(string parameter,string parameterValue)
        {
            if(parameter != null && parameter != "")
            {
                if(parameters.Contains(parameter))
                {
                    parameters.Remove(parameter);
                }

                parameters.Add(parameter,parameterValue);
            }
        }

        /** 是否财付通签名,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
         * @return boolean */
        public virtual Boolean isTenpaySign()
        {
            StringBuilder sb = new StringBuilder();

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

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

            sb.Append("key=" + this.getKey());
            string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToLower();
            this.setDebugInfo(sb.ToString() + " => sign:" + sign);
            //debug信息
            return getParameter("sign").ToLower().Equals(sign);
        }

        //判断微信签名
        public virtual Boolean isWXsign()
        {
            StringBuilder sb = new StringBuilder();
            Hashtable signMap = new Hashtable();

            foreach (string k in xmlMap.Keys)
            {
                if (k != "SignMethod" && k != "AppSignature")
                {
                    signMap.Add(k.ToLower(), xmlMap[k]);
                }
            }
            signMap.Add("appkey", this.appkey);

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

            foreach (string k in akeys)
            {
                string v = (string)signMap[k];
                if (sb.Length == 0)
                {
                    sb.Append(k + "=" + v);
                }
                else
                {
                    sb.Append("&" + k + "=" + v);
                }
            }

            string sign = SHA1Util.getSha1(sb.ToString()).ToString().ToLower();

            this.setDebugInfo(sb.ToString() + " => SHA1 sign:" + sign);

            return sign.Equals(xmlMap["AppSignature"]);

        }

        //判断微信维权签名
        public virtual Boolean isWXsignfeedback()
        {
            StringBuilder sb = new StringBuilder();
            Hashtable signMap = new Hashtable();

            foreach (string k in xmlMap.Keys)
            {
                if (SignField.IndexOf(k.ToLower()) != -1)
                {
                    signMap.Add(k.ToLower(), xmlMap[k]);
                }
            }
            signMap.Add("appkey", this.appkey);

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

            foreach (string k in akeys)
            {
                string v = (string)signMap[k];
                if ( sb.Length == 0 )
                {
                    sb.Append(k + "=" + v);
                }
                else
                {
                    sb.Append("&" + k + "=" + v);
                }
            }

            string sign = SHA1Util.getSha1(sb.ToString()).ToString().ToLower();

            this.setDebugInfo(sb.ToString() + " => SHA1 sign:" + sign);

            return sign.Equals( xmlMap["AppSignature"] );

        }

        /** 获取debug信息 */
        public string getDebugInfo()
        { return debugInfo;}

        /** 设置debug信息 */
        protected void setDebugInfo(String debugInfo)
        { this.debugInfo = debugInfo;}

        protected virtual string getCharset()
        {
            return this.httpContext.Request.ContentEncoding.BodyName;

        }

    }
}

SHA1Util:

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;

namespace tenpayApp
{
    class SHA1Util
    {
        public static String getSha1(String str)
        {
            //建立SHA1对象
            SHA1 sha = new SHA1CryptoServiceProvider();
            //将mystr转换成byte[]
            ASCIIEncoding enc = new ASCIIEncoding();
            byte[] dataToHash = enc.GetBytes(str);
            //Hash运算
            byte[] dataHashed = sha.ComputeHash(dataToHash);
            //将运算结果转换成string
            string hash = BitConverter.ToString(dataHashed).Replace("-", "");
            return hash;
        }
    }
}

TenpayUtil:

using System;
using System.Text;
using System.Web;
namespace tenpayApp
{
    /// <summary>
    /// TenpayUtil 的摘要说明。
    /// 配置文件
    /// </summary>
    public class TenpayUtil
    {
        public static string tenpay = "1";
        public static string partner = "";                   //商户号
        public static string key = "";  //密钥
        public static string appid = "";//appid
        public static string appkey = "";//paysignkey(非appkey)
        public static string tenpay_notify = "http://localhost/payNotifyUrl.aspx"; //支付完成后的回调处理页面,*替换成notify_url.asp所在路径

        public TenpayUtil()
        {

        }
        public static string getNoncestr()
        {
            Random random = new Random();
            return MD5Util.GetMD5(random.Next(1000).ToString(), "GBK");
        }

        public static string getTimestamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        /** 对字符串进行URL编码 */
        public static string UrlEncode(string instr, string charset)
        {
            //return instr;
            if(instr == null || instr.Trim() == "")
                return "";
            else
            {
                string res;

                try
                {
                    res = HttpUtility.UrlEncode(instr,Encoding.GetEncoding(charset));

                }
                catch (Exception ex)
                {
                    res = HttpUtility.UrlEncode(instr,Encoding.GetEncoding("GB2312"));
                }

                return res;
            }
        }

        /** 对字符串进行URL解码 */
        public static string UrlDecode(string instr, string charset)
        {
            if(instr == null || instr.Trim() == "")
                return "";
            else
            {
                string res;

                try
                {
                    res = HttpUtility.UrlDecode(instr,Encoding.GetEncoding(charset));

                }
                catch (Exception ex)
                {
                    res = HttpUtility.UrlDecode(instr,Encoding.GetEncoding("GB2312"));
                }

                return res;

            }
        }

        /** 取时间戳生成随即数,替换交易单号中的后10位流水号 */
        public static UInt32 UnixStamp()
        {
            TimeSpan ts = DateTime.Now - TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            return Convert.ToUInt32(ts.TotalSeconds);
        }
        /** 取随机数 */
        public static string BuildRandomStr(int length)
        {
            Random rand = new Random();

            int num = rand.Next();

            string str = num.ToString();

            if(str.Length > length)
            {
                str = str.Substring(0,length);
            }
            else if(str.Length < length)
            {
                int n = length - str.Length;
                while(n > 0)
                {
                    str.Insert(0, "0");
                    n--;
                }
            }

            return str;
        }

    }
}

页面代码:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using tenpayApp;
//=================================
//JSAPI支付
//=================================
public partial class _Default : System.Web.UI.Page
{
    public String appId = TenpayUtil.appid;
    public String timeStamp = "";
    public String nonceStr = "";
    public String packageValue = "";
    public String paySign = "";

    protected void Page_Load(object sender, EventArgs e)
    {
        string sp_billno = Request["order_no"];
        //当前时间 yyyyMMdd
        string date = DateTime.Now.ToString("yyyyMMdd");

        if (null == sp_billno)
        {
            //生成订单10位序列号,此处用时间和随机数生成,商户根据自己调整,保证唯一
            sp_billno = DateTime.Now.ToString("HHmmss") + TenpayUtil.BuildRandomStr(4);
        }
        else
        {
            sp_billno = Request["order_no"].ToString();
        }

        sp_billno = TenpayUtil.partner + sp_billno;

        //创建支付应答对象
        RequestHandler packageReqHandler = new RequestHandler(Context);
        //初始化
        packageReqHandler.init();

        //设置package订单参数
        packageReqHandler.setParameter("partner", TenpayUtil.partner);          //商户号
        packageReqHandler.setParameter("fee_type", "1");                    //币种,1人民币
        packageReqHandler.setParameter("input_charset", "GBK");
        packageReqHandler.setParameter("out_trade_no", sp_billno);        //商家订单号
        packageReqHandler.setParameter("total_fee", "1");                    //商品金额,以分为单位(money * 100).ToString()
        packageReqHandler.setParameter("notify_url", TenpayUtil.tenpay_notify);            //接收财付通通知的URL
        packageReqHandler.setParameter("body", "JSAPIdemo");                        //商品描述
        packageReqHandler.setParameter("spbill_create_ip", Page.Request.UserHostAddress);   //用户的公网ip,不是商户服务器IP

        //获取package包
        packageValue = packageReqHandler.getRequestURL();

        //调起微信支付签名
        timeStamp = TenpayUtil.getTimestamp();
        nonceStr = TenpayUtil.getNoncestr();

        //设置支付参数
        RequestHandler paySignReqHandler = new RequestHandler(Context);
        paySignReqHandler.setParameter("appid", appId);
        paySignReqHandler.setParameter("appkey", TenpayUtil.appkey);
        paySignReqHandler.setParameter("noncestr", nonceStr);
        paySignReqHandler.setParameter("timestamp", timeStamp);
        paySignReqHandler.setParameter("package", packageValue);
        paySign = paySignReqHandler.createSHA1Sign();

        //获取debug信息,建议把请求和debug信息写入日志,方便定位问题
        //string pakcageDebuginfo = packageReqHandler.getDebugInfo();
        //Response.Write("<br/>pakcageDebuginfo:" + pakcageDebuginfo + "<br/>");
        //string paySignDebuginfo = paySignReqHandler.getDebugInfo();
        //Response.Write("<br/>paySignDebuginfo:" + paySignDebuginfo + "<br/>");

    }
}

时间: 2024-10-05 05:21:08

[转载]微信支付的相关文章

微信支付,别人遇到的坑--转载

微信支付,别人遇到的坑: http://blog.csdn.net/ahence/article/details/50173621 http://www.360doc.com/content/15/0214/10/7044580_448519997.shtml

ectouch 微信支付成功后订单状态未改变的解决办法 (转载)

原文地址: 微信支付支付成功后,返回到mobile/wx_native_callback.php 之前代码 define('IN_ECS', true); require(dirname(__FILE__) . '/include/init.php'); require(ROOT_PATH . 'include/lib_payment.php'); require_once(ROOT_PATH .'include/modules/payment/wx_new_jspay.php'); $paym

微信小程序篇(微信小程序的支付)转载 “微信小程序联盟”

微信小程序的支付和微信公众号的支付是类似的,对比起来还比公众号支付简单了一些,我们只需要调用微信的统一下单接口获取prepay_id之后我们在调用微信的支付即可. 今天我们来封装一般node的支付接口!!! 首先调用统一下单接口我们需要知道一些信息 var bookingNo = 'davdian' + this.createNonceStr() + this.createTimeStamp() var deferred = Q.defer() var appid = config.appId

微信支付(转载一)

Android微信支付 2014-08-09 一.使用微信官方的提供的demo里的appid等 1.微信接口上手指南:(从“移动应用开发”->“Android接入指南”)建议,先把官方这篇文章看完 2.微信支付接口(从“移动应用开发”->“Android开发手册” )(下载官方demohttps://res.wx.qq.com/paymchres/zh_CN/htmledition/download/wxpay/app_wx_pay_tool_android1d902c.zip) Androi

微信支付(转载二)

微信支付现在主要集成在:1.移动应用开发  2.网站应用开发  3.公众账号开发 本篇主要针对移动应用App集成微信支付,实际项目坑点分享! 一.既予之.与共之:平台资源 1.微信开放平台:https://open.weixin.qq.com/ 2.微信公众平台:https://mp.weixin.qq.com/ 3.微信支付指引和资源中心:微信支付接入指南和资源下载中心<强力推荐阅读> https://open.weixin.qq.com/cgi-bin/frame?t=resource/r

Android开发 --微信支付开发(转载!)(开发工具:Eclipse)

Android_APP 微信支付接口开发 日期:2015-10-06 12:47:33 作者: 来源: 人气:3549 1.首先说一下我们在开发微信支付接口的时候遇到最多和最疑惑的问题,那就是明明 appid.商户号.API密钥 都对照了好几遍确实是和自己的一样,并且也没有在Log日志中出现签名错误等信息,却始终调不起微信支付,或是直接回到支付结果后的界面并提示 “微信支付结果:null;code=-1”.这就是微信支付中的一个深坑之处(为什么说这是深坑之处呢?会在下面特别说明). 2.下面就教

微信支付,支付宝支付,银联支付——三大支付总结

转载:  https://juejin.im/post/596d97576fb9a06bb874a812 银联支付,支付宝支付,微信支付的三大总结,之前也有写过两篇. 微信支付,支付宝支付,银联支付--三大支付总结: http://blog.csdn.net/androidstarjack/article/details/72669394 支付宝植入总结: android 支付宝的植入 <曾经踩过的坑> 微信支付总结: Android 微信支付总结 备注:出于安全考虑,验签我们都是放到后台进行

MD5加密支付宝支付与微信支付

在做支付宝支付与微信支付时看到两家公司给的dom其中关于MD5加密的 支付宝的dom: DigestUtils.md5Hex(test).toUpperCase(); 微信的dom: private static String MD5(String sourceStr) throws UnsupportedEncodingException { String result = ""; try { MessageDigest md = MessageDigest.getInstance(

atitit.微信支付的教程文档 attilax总结

atitit.微信支付的教程文档 attilax总结 1. 支付流程概览 1 2. 设置支付起始目录   host/app/paydir/ 1 3. 设置oauth验证域名 1 4. 测试目录 可以使用ip,但必须80端口好像. 1 5. 发起测试支付,菜单  host/fromother.jsp 2 6. Start.jsp 2 7. 获取openid的page接口,并制定回调接口 2 8. 开始支付页面 3 9. 生成js调用支付接口 4 10. 注意事项 5 10.1. 预支付的签名and