当前位置: 首页 > news >正文

billplz可以沙箱测试

请求https://www.billplz-sandbox.com/api/v3

collection_id和apikey自己去https://main.billplz-sandbox.com/或https://sso.billplz-sandbox.com/网址用自己邮箱申请沙箱帐号来获取collection_id和apikey

调用billplz账单

public void ProcessRequest(HttpContext context) { if (context.Request.Cookies["wb163CmsUserFirst"]["UserID"] == null) { context.Response.Write("{\"status\":\"2\",\"url\":\"用户未登录\"}"); return; } // 在文件顶部添加 using System.Net; ServicePointManager.Expect100Continue = true; // 启用 TLS1.2(和 TLS1.1 可选) ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072 | (SecurityProtocolType)768; // 仅测试环境可临时允许不验证证书(生产环境不要启用) //ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; try { decimal amount = 0m; string _baseUrl = "https://www.billplz.com/api/v3"; //string _baseUrl = "https://www.billplz-sandbox.com/api/v3"; wb163Cms.Models.WebSet webset = new wb163Cms.BLL.BLL_WebSet().loadConfig(System.Web.Hosting.HostingEnvironment.MapPath(ConfigurationManager.AppSettings["Configpath"].ToString())); amount = Convert.ToDecimal(context.Request.Params["amount"].Trim()); string paytime = context.Request.Params["paytime"].Trim(); // Billplz amount is in cents (sen) — multiply by 100 int amountSen = (int)Math.Round(amount * 100m); amountSen += 100; var payload = new { collection_id = webset.billplzcollection_id, //collection_id=webset.billplzsandcollection_id, name = wb163Cms.Common.DEncrypt.DEncrypt.Decrypt(context.Request.Cookies["wb163CmsUserFirst"]["UserID"].ToString()), email = "123@gmail.com", amount = amountSen, callback_url = webset.WebUrl+"Tools/BillplzHook.ashx",//支付成功回调函数 redirect_url = webset.WebUrl+"user.html", description = "11", reference_1 = amountSen+"" }; string url = _baseUrl + "/bills"; var req = (HttpWebRequest)WebRequest.Create(url); req.Method = "POST"; req.ContentType = "application/json"; // Basic auth: username = API key, password = empty string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes(webset.billplzapikey + ":")); //string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes(webset.billplzsandapikey + ":")); req.Headers["Authorization"] = "Basic " + auth; string json = JsonConvert.SerializeObject(payload); byte[] data = Encoding.UTF8.GetBytes(json); req.ContentLength = data.Length; using (var s = req.GetRequestStream()) { s.Write(data, 0, data.Length); } try { using (var resp = (HttpWebResponse)req.GetResponse()) using (var sr = new StreamReader(resp.GetResponseStream())) { string respText = sr.ReadToEnd(); Bill bill = JsonConvert.DeserializeObject<Bill>(respText); context.Response.Write("{\"status\":\"1\",\"url\":\""+bill.Url+"\"}"); return; } } catch (WebException wex) { using (var r = wex.Response as HttpWebResponse) { if (r != null) { using (var sr = new StreamReader(r.GetResponseStream())) { string error = sr.ReadToEnd(); throw new Exception("Billplz API error: " + error); } } throw; } } if (true) { context.Response.Write("1"); return; } } catch (Exception ex) { context.Response.Write("{\"status\":\"2\",\"url\":\"\"}"); return; } }

回调函数BillplzHook.ashx

public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; string body; using (var reader = new StreamReader(context.Request.InputStream)) { body = reader.ReadToEnd(); } wb163Cms.Models.WebSet webset = new wb163Cms.BLL.BLL_WebSet().loadConfig(System.Web.Hosting.HostingEnvironment.MapPath(ConfigurationManager.AppSettings["Configpath"].ToString())); //string xSignatureKey = webset.billplzsandXSignaturekey; string xSignatureKey = webset.billplzXSignaturekey; try { var dict = ParseQueryString(body); if (!dict.TryGetValue("x_signature", out string receivedSignature)) { context.Response.StatusCode = 500; context.Response.Write("error"); } bool isValid = VerifySignature(dict, xSignatureKey, receivedSignature); string paid = dict.TryGetValue("paid", out var paid1) ? paid1 : "";//支付成功状态 string amount = dict.TryGetValue("amount", out var amount1) ? amount1 : "";//金额 string userid = dict.TryGetValue("name", out var userid1) ? userid1 : "";//用户id decimal money = Convert.ToDecimal(amount) / 100M;//马币单位是仙要除去100才能是1马币 money -= 1M; BLL_User ubll = new BLL_User(); wb163Cms.Models.User modeluser = ubll.GetModel(int.Parse(userid)); if (paid == "true"&&isValid)//支付成功 { //充值直接审核 wb163Cms.BLL.BLL_MoneyPay bll = new BLL.BLL_MoneyPay(); wb163Cms.Models.MoneyPay model = new Models.MoneyPay(); model.UserName = modeluser.UserName; model.UserID = modeluser.Id; model.Pic = ""; model.User_note = ""; model.RefNo = ""; model.Payway = 0; model.BankName = "在线支付"; model.Mongeytype = 0; model.Entermoney = money; model.Paytime = DateTime.Now; model.Status = 1; model.Addtime = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); model.Checktime = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); model.Oppter = ""; model.Oppter_note = ""; model = bll.Add(model); //wb163Cms.BLL.BLL_User blluser = new BLL.BLL_User(); //充值记录 wb163Cms.BLL.BLL_User_charge_record bllrecord = new BLL.BLL_User_charge_record(); wb163Cms.Models.User_charge_record modelrecord = new Models.User_charge_record(); modelrecord.Amount = money; modelrecord.Balance = modeluser.Point; modelrecord.Currency = "RM"; modelrecord.Afterpay = modelrecord.Balance + modelrecord.Amount; modelrecord.Posttime = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); modelrecord.Type = 1; modelrecord.Remark = "提交充值审核通过"; modelrecord.User_id = model.UserID; bllrecord.Add(modelrecord); //更新余额 modeluser.Point += model.Entermoney; ubll.Update(modeluser); //ubll.UpdateField(userid, " point=point+" + money + " ");//更新余额 //context.Response.Redirect("/user.html"); context.Response.StatusCode = 200; context.Response.Write("ok"); } else { wb163Cms.Common.FsLog.CreateLog("billplz 更新报错", true); context.Response.StatusCode = 500; context.Response.Write("error"); } } catch (Exception ex) { // 记录日志 wb163Cms.Common.FsLog.CreateLog("billplz webhook error:" + ex.Message, true); context.Response.StatusCode = 500; context.Response.Write("error"); } } //解析&分隔的数据为Dictionary static Dictionary<string, string> ParseQueryString(string qs) { var result = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrEmpty(qs)) return result; // 如果传入的是完整 URL,截取 ? 之后的查询部分 int q = qs.IndexOf('?'); if (q >= 0) qs = qs.Substring(q + 1); var parts = qs.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries); foreach (var part in parts) { int eq = part.IndexOf('='); string key, value; if (eq >= 0) { key = part.Substring(0, eq); value = part.Substring(eq + 1); } else { key = part; value = string.Empty; } // 使用 WebUtility.UrlDecode 做解码(处理 %xx 和 +) key = WebUtility.UrlDecode(key ?? string.Empty); value = WebUtility.UrlDecode(value ?? string.Empty); result[key] = value; } return result; } //验签 public static bool VerifySignature(Dictionary<string, string> parameters, string xSignatureKey, string receivedSignature) { if (parameters == null || string.IsNullOrEmpty(xSignatureKey) || string.IsNullOrEmpty(receivedSignature)) return false; // 1. 按照键名 ASCII 升序排列,并拼接成 key1value1key2value2 格式 var sortedParams = parameters .Where(p => !string.IsNullOrEmpty(p.Key) && p.Key != "x_signature") // 确保排除 x_signature .OrderBy(p => p.Key+p.Value, StringComparer.Ordinal); var sourceString = new StringBuilder(); foreach (var param in sortedParams) { sourceString.Append(param.Key).Append(param.Value+"|"); } sourceString.Remove(sourceString.Length - 1, 1); Common.FsLog.CreateLog("签名"+sourceString.ToString(), true); // 2. 使用 HMAC-SHA256 计算签名 var encoding = new UTF8Encoding(); byte[] keyBytes = encoding.GetBytes(xSignatureKey); byte[] messageBytes = encoding.GetBytes(sourceString.ToString()); using (var hmac = new HMACSHA256(keyBytes)) { byte[] hashBytes = hmac.ComputeHash(messageBytes); string calculatedSignature = BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant(); // 3. 比对计算出的签名与接收到的签名 return string.Equals(calculatedSignature, receivedSignature, StringComparison.OrdinalIgnoreCase); } }
http://www.jsqmd.com/news/1163116/

相关文章:

  • PG 日报|pg_dump 全平台支持多线程并行
  • 如何用 ElevenLabs 给自己的视频配专业 AI 旁白?
  • 南京处理离婚财产分割专业律所律师 - AZJ888
  • 高淳区离婚财产分割胜诉律师:以专业确定性守护你的财产权益 - AZJ888
  • 压电蜂鸣器EPT-14A4005P驱动与优化方案
  • 专治叛逆厌学!2026湖南永州市正规文武学校,凤凰育英民族学校家长口碑爆棚 - 全国文武学校招生
  • Adobe-GenP破解工具终极指南:3分钟免费激活Adobe全家桶的完整解决方案
  • 如何一键为qBittorrent安装20+搜索插件,告别繁琐的资源寻找
  • WhatsApp 消息定时发送与任务调度系统的设计实践
  • cpp_redis管道化技术详解:提升Redis操作性能的10个技巧
  • ncmdump:高效实用的NCM音频解密工具,快速解锁网易云音乐格式限制
  • 2026 南京建邺黄金回收实测|河西正规实体门店汇总,卖旧金、金条零套路避坑指南 - 福金阁黄金回收
  • 南京打离婚财产分割官司律师|高净值财产纠纷专业应诉 - AZJ888
  • TB9051FTG驱动直流电机的超静音PWM控制方案
  • 高淳区离婚夫妻存款分割律师:穿透资金迷雾,拿回属于您的每一分积蓄 - AZJ888
  • Nemotron-Labs-Audex-30B-A3B多模态能力评测:在12个标准基准测试中的表现分析
  • 南京父母出资买房离婚分割律师:以精细甄别守护家庭房产的公平归属 - AZJ888
  • CTPersistance完全指南:iOS SQLite持久化层的终极解决方案
  • MCP Scanner架构深度剖析:5大核心组件如何协同工作保障AI安全
  • 新手必读:理解llama-nemotron-embed-vl-1b-v2中图像与文本嵌入的基本概念
  • 计算机毕业设计之基于SSM的园林花卉仓库管理系统
  • 拒绝低价乱账!2026福州正规代理记账口碑排行TOP4 资质/本地化/服务全维度实测 - 互联网科技品牌测评
  • WebPShop:为Photoshop提供专业级WebP格式支持的终极解决方案
  • API中转站主备线路设计:Token 和 Base URL 如何成对切换
  • eShopOnAbp测试策略:单元测试与集成测试完整指南
  • 高淳区离婚隐匿财产追回律师|婚内转移资产财产纠纷维权 - AZJ888
  • EPT-14A4005P压电蜂鸣器驱动与优化方案
  • 学生党AI编程工具选型指南:从补全到自治Agent的实战决策
  • 只懂采购永远升不上总监!SCMP 项目补齐全链路短板,中研供应链实战课打破中层天花板
  • AI图像分层终极指南:如何快速将单图转换为可编辑的PSD图层