1.设置JS安全域名
2.开通微信支付,并在商户端设置支付安全域名
3.获取JSAPI权限参数
/// <summary> /// jsapi获取签名 /// </summary> private config QuerySignature(string access_token,string ticket,string ticket_time,int weixin_id,string appid) { //需要签名的页面的url string urlstr = Util.getServerPath() + "/Home/TemplateView"; //获取最新的jsapi_tiket与accesstoken WeixinJsAPI jsAPi = new WeixinJsAPI(access_token, ticket, ticket_time, weixin_id); string jsapi = jsAPi.Ticket; //取签名的时间戳可以是随机数 long timestamp = Util.getLongTime(); //随机字符串(可以写方法随机生成) string nonceStr = sys.getRandomCode(26); //签名算法 string signature = GetSignature(jsapi, nonceStr, timestamp, urlstr); return new config() {appId= appid,nonceStr= nonceStr,timestamp= timestamp,signature= signature }; }
/// <summary> /// 签名算法 /// </summary> /// <param name="jsapi">ticket</param> /// <param name="nonceStr">随机字符串</param> /// <param name="timestamp">时间戳</param> /// <param name="urlstr">需要签名的url</param> private string GetSignature(string jsapi, string nonceStr, long timestamp, string urlstr) { StringBuilder str = new StringBuilder(); string string1 = "jsapi_ticket=" + jsapi + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + urlstr; return FormsAuthentication.HashPasswordForStoringInConfigFile(string1, "SHA1").ToLower(); }
/*产生验证码*/ public static string getRandomCode(int codeLength) { string so = "2,3,5,6,7,8,9,A,B,C,D,E"; string[] strArr = so.Split(','); string code = ""; Random rand = new Random(); for (int i = 0; i < codeLength; i++) { code += strArr[rand.Next(0, strArr.Length)]; } return code; }
还需要获取微信公众号的JSAPI的ticket
4.统一下单
/// <summary> /// codebook_hifun_net的统一下单,主要是朗诵与笔顺 /// </summary> /// <param name="orderform_id"></param> /// <param name="openid"></param> /// <param name="appcode"></param> /// <returns></returns> private chooseWXPay GetHifunNetData(int orderform_id,string openid,string appcode,string seedName, string notifyUrl,weixin_net weixin, string weixin_applet_path,out double money,out string orderform_number) { money = 0; orderform_number = ""; DataHelper db = new DataHelper(); orderform_net orderform = db.GetModelById<orderform_net>("orderform", orderform_id.ToString()); if (orderform.status == "S99") { LogHelper.Info("已支付订单,不需要重复支付"); return new chooseWXPay() { timestamp=0,signType="0",nonceStr="0",paySign="0",package="0",is_pay = true }; } LogHelper.Info("orderform数据:" + Newtonsoft.Json.JsonConvert.SerializeObject(orderform)); //weixin_net weixin = db.GetModelById<weixin_net>("weixin", "334"); weixin_applet_net weixin_applet = db.GetModelBySql<weixin_applet_net>($@"select * from weixin_applet where appcode='{appcode}'"); //微信公众号统一下单 (需要将数据库weixin的信息补全) WeixinPay weixinPay = new WeixinPay(System.Web.HttpContext.Current, weixin.appid, weixin.appsecret, weixin.pay_mch_id, weixin.pay_partner_key); string payNumber = Common.Orderform.Orderform.getNewPayNumer(orderform.uid.ToString()); //微信支付,统一下单(与微信支付订单一样) UnifiedOrder unifiedOrder = new UnifiedOrder(); int total_fee = int.Parse(((orderform.money + orderform.freight) * 100).To<double>().ToString("F0")); money = orderform.money??0 + orderform.freight??0; unifiedOrder.nonce_str = sys.getRandomCode(26); unifiedOrder.body = seedName + "(" + appcode + "-Applet)"; unifiedOrder.out_trade_no = payNumber;//商户单号使用支付单号 unifiedOrder.total_fee = total_fee; unifiedOrder.spbill_create_ip = Util.GetUserIp(); unifiedOrder.notify_url = notifyUrl; //回调 unifiedOrder.trade_type = "JSAPI"; unifiedOrder.openid = openid; orderform_number = payNumber; //获得统一下单返回的支付单信息 UnifiedOrderReturn unifiedOrderReturn = weixinPay.UnifiedOrder(unifiedOrder); LogHelper.Info("统一下单返回的支付单信息:" + Newtonsoft.Json.JsonConvert.SerializeObject(unifiedOrderReturn)); if ("SUCCESS".Equals(unifiedOrderReturn.return_code)) { //准备获取支付信息的签名参数 Hashtable parameter = new Hashtable(); parameter.Add("appId", unifiedOrderReturn.appid); parameter.Add("timeStamp", Util.getLongTime().ToString()); parameter.Add("nonceStr", unifiedOrderReturn.nonce_str); parameter.Add("package", "prepay_id=" + unifiedOrderReturn.prepay_id); parameter.Add("signType", "MD5"); string paysign = weixinPay.Sign(parameter); chooseWXPay weixinPayInfo = new chooseWXPay() { //appId = unifiedOrderReturn.appid, timestamp = Util.getLongTime(), nonceStr = unifiedOrderReturn.nonce_str, package = "prepay_id=" + unifiedOrderReturn.prepay_id, signType = "MD5", paySign = paysign, is_pay = false //orderformId = orderform.id }; LogHelper.Info("获得了统一下单数据:" + Newtonsoft.Json.JsonConvert.SerializeObject(weixinPayInfo)); // //创建支付记录(未支付状态),便于通知回调Update pay_record_net payRecord = new pay_record_net { pay_number = payNumber, unionnumber = orderform.unionnumber, pay_code = "WEIXIN_APPLET", pay_sales_id = weixin_applet.id, pay_money = (orderform.money + orderform.freight).To<double>(), pay_uid = orderform.uid??0, space_id = 0, channel_id = 0, createtime = DateTime.Now, prepay_id = unifiedOrderReturn.prepay_id }; db.Insert("pay_record", payRecord); //添加支付成功后的模板消息 weixin_template_success_pay_net weixin_template_success_pay = new weixin_template_success_pay_net() { pay_number = payNumber, is_send_success = 0, error_message = "", create_time = DateTime.Now, openid = openid, weixin_applet_appid = weixin_applet.appid, weixin_applet_page = weixin_applet_path, weixin_id = weixin.id, seed_name=seedName, }; db.Insert("weixin_template_success_pay", weixin_template_success_pay); return weixinPayInfo; } else { //删除订单 orderform.isdelete = 1; orderform.remarks = "小程序统一下单失败,自动删除"; db.Update("orderform", orderform, "id="+orderform_id); } return null; }
5.返回给页面
@model Tlkjbase.Models.WeixinH5Pay @{ Layout = null; var config = Model.config; var chooseWXPay = Model.chooseWXPay; } <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link href="~/Content/css/wxpay1.css" rel="stylesheet" /> <script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> <script src="~/Scripts/wxpay.js"></script> <script src="~/Scripts/jquery-1.10.2.min.js"></script> <title>订单支付</title> </head> <body> @if (Model.success) { <header class="top">微信安全支付</header> <div class="main-content"> <div class="title">小程序支付</div> <div class="price">¥<span>@Model.money</span></div> <div class="pay-info">商品名称:<div class="info-detail">@Model.seedName</div></div> <div class="pay-info">支付时间:<div class="info-detail">@Model.payDate</div></div> <div class="pay-info">支付单号:<div class="info-detail">@Model.orderform_number</div></div> <div class="pay-info">支付方式:<div class="info-detail">微信支付</div></div> </div> <div class="button" id="SubmitPay">确认支付</div> <script> window.onload = () => { var doc = document; var docEl = doc.documentElement; var width = docEl.getBoundingClientRect().width; var rem = width * 100 / 750; docEl.style.fontSize = rem + "px"; wx.config({ debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '@config.appId', // 必填,公众号的唯一标识 timestamp: @config.timestamp, // 必填,生成签名的时间戳 nonceStr: '@config.nonceStr', // 必填,生成签名的随机串 signature: '@config.signature',// 必填,签名 jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表 }); document.getElementById('SubmitPay').onclick=function() { submitPay(); }; } var submitPay = function(){wx.chooseWXPay({ timestamp: @chooseWXPay.timestamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 nonceStr: '@chooseWXPay.nonceStr', // 支付签名随机串,不长于 32 位 package: '@chooseWXPay.package', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*) signType:'@chooseWXPay.signType', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5' paySign: '@chooseWXPay.paySign', // 支付签名 success: function (res) { // 支付成功后的回调函数 alert("支付成功"); wx.closeWindow(); } })}; </script> } else { <div class="hint">@Model.message</div> <script> window.onload = () => { var doc = document; var docEl = doc.documentElement; var width = docEl.getBoundingClientRect().width; var rem = width * 100 / 750; docEl.style.fontSize = rem + "px"; } </script> } </body> </html>
6.发送模板消息
/// <summary> /// 组织发送模板消息内容 /// </summary> /// <param name="weixin">微信公众号信息</param> /// <param name="templateCode">模板消息:OPENTM200654400</param> /// <param name="openid">用户在公众号下的openid</param> /// <param name="data">{{first.DATA}} 商家名称:{{keyword1.DATA}} 商家电话:{{keyword2.DATA}} 订单号:{{keyword3.DATA}} 状态:{{keyword4.DATA}} 总价:{{keyword5.DATA}} {{remark.DATA}}</param> /// <returns></returns> public static string sendWeixinTemplate(orderform orderform, weixin weixin, string templateCode, string openid, string data, string seedName, string appcode, string weixin_applet_path) { BaseBLL<weixin_template> templateBll = new BaseBLL<weixin_template>(); weixin_template Template = templateBll.Find(x => x.template_code == templateCode && x.weixin_id == weixin.id); //组织发送的数据 string[] valueArray = data.Split(';'); JObject _data = JObject.Parse("{}"); for (int i = 0; i < valueArray.Length; i++) { if (i == 0) { JObject subObject = new JObject( new JProperty("value", valueArray[i]), new JProperty("color", "#173177") ); _data.Add("first", subObject); } else if (i == valueArray.Length - 1) { JObject subObject = new JObject( new JProperty("value", valueArray[i]), new JProperty("color", "#173177") ); _data.Add("remark", subObject); } else { JObject subObject = new JObject( new JProperty("value", valueArray[i]), new JProperty("color", "#333") ); _data.Add("keyword" + (i), subObject); } } WeixinAPI weixinXApi = new WeixinAPI(weixin.appid, weixin.appsecret, weixin.access_token, weixin.access_token_time.ToString(), weixin.id); JObject postData = JObject.Parse("{}"); postData.Add("touser", openid); postData.Add("template_id", Template.tempid); postData.Add("url", "https://JS安全域名/?orderform_id=" + orderform.id + "&openid=" + openid + "&weixin_id=" + weixin.id + "&appcode=" + appcode + "&seedName=" + seedName + "&weixin_applet_path=" + weixin_applet_path + "¬ifyUrl=" + Util.getServerPath()); postData.Add("data", _data); return weixinXApi.sendTemplateByPublic(postData.ToString()); }
public string sendTemplateByPublic(string postData) { LogHelper.Info("sendTemplate:" + postData); string url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + AccessToken; return HttpHelper.HttpPost(url, postData); }