- 【C#】WechatPay-API-v3 使用平台证书加密内容与应答|通知验签(SHA256 with RSA)
/// <summary> /// 使用微信支付平台证书公钥加密验签 /// https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/qian-ming-yan-zheng /// </summary> public class WXPlatform { public string PublicKey { get; private set; } private byte[] _publicKeyBytes { get; set; } /// <summary> /// 构造方法 /// </summary> /// <param name="publickey">-----BEGIN CERTIFICATE----- 开头的string,转为bytes->不需要每次都去</param> public WXPlatform(string publickey) { this.PublicKey = publickey; this._publicKeyBytes = Encoding.UTF8.GetBytes(publickey); } /// <summary> /// 最终提交请求时,需对敏感信息加密,如身份证、银行卡号。 /// 加密算法是RSA,使用从接口下载到的公钥进行加密,非后台下载到的私钥。 /// </summary> /// <param name="text">要加密的明文</param> /// <param name="publicKey"> </param> /// <returns></returns> public string Encrypt(string text) { var x509 = new X509Certificate2(this._publicKeyBytes); using (var rsa = (RSACryptoServiceProvider)x509.PublicKey.Key) { var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), true); return Convert.ToBase64String(buff); } } /// <summary> /// 验证签名 /// </summary> /// <param name="signedString">私钥加密串-Wechatpay-Signature</param> /// <param name="signSourceString">验签名串-应答时间戳\n应答随机串\n应答报文主体\n</param> /// <returns></returns> public bool VerifySign(string signedString, string signSourceString) { var x509 = new X509Certificate2(this._publicKeyBytes); using (var rsa = (RSACryptoServiceProvider)x509.PublicKey.Key) { using (var sha256 = new SHA256CryptoServiceProvider()) { var b = rsa.VerifyData(Encoding.UTF8.GetBytes(signSourceString), sha256, Convert.FromBase64String(signedString)); return b; } } } }
2020-02-29 - 添加分账接收方签名失败
微信支付接口签名校验工具https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=20_1 能校验成功, [图片] 放到代码里,响应回的数据就是失败,不知道原因在哪里?请协助看看,非常感谢谢。 以下为日志输出到的响应数据。 [图片] 已经按下面的步骤检查过了,还是没找到问题所在。 [图片] 重置过API密钥也还是不行。 所有的都检查了一遍,没发现问题在哪里。 能不能协助看看,非常感谢。
2019-04-28 - .net 添加分账接收方【普通直连分账】
public ActionResult AddReceiver() { WeixinTrace.Log("rnrn----------------------------添加分账接收方-----------------------------------------------rnrn"); Logger logger = LogManager.GetLogger("SimpleDemo"); string receiver = " { "type":"PERSONAL_WECHATID","account":"zuoann2012","name":"小李飞刀","relation_type":"PARTNER" } "; string mch_id = Globals.Configuration["AppSettings:TenPayV3_MchId"].ToString(); string appid = Globals.Configuration["AppSettings:WxOpenAppId"].ToString(); string TenPayV3_Key = Globals.Configuration["AppSettings:TenPayV3_Key"].ToString(); string nonce_str = TenPayV3Util.GetNoncestr(); string stringA = "appid=" + appid + "&mch_id=" + mch_id + "&nonce_str=" + nonce_str+ "&receiver="+ receiver; string stringSignTemp = stringA + "&key=" + TenPayV3_Key; //注:key为商户平台设置的密钥key string sign = EncryptHelper.GetHmacSha256(stringSignTemp, TenPayV3_Key).ToUpper(); Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("mch_id", mch_id); dic.Add("appid", appid); dic.Add("nonce_str", nonce_str); dic.Add("sign", sign); dic.Add("receiver", receiver); StringBuilder sb = new StringBuilder(); sb.Append("<xml>"); foreach (string k in dic.Keys) { string v = (string)dic[k]; sb.Append("<" + k + ">" + v + "</" + k + ">"); } sb.Append("</xml>"); string post_xml = sb.ToString(); logger.Info("rnrn********************************post_xml************************************rnrn"); logger.Info(post_xml); string result = HttpPost("https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver", post_xml); logger.Info("rnrn*********************************返回值************************************rnrn"); logger.Info(result); return Content(result); }
2019-09-10 - 微信官网关于调高分账比例的让联系BD,有没有联系到的兄弟?
目前微信支付分账的比例最高是30%,我看专区里面有问如何调高分账比例,微信官方的回答是联系BD,请问如何联系,有没有联系到的兄弟,支个招呗??
2019-12-23 - 添加分账接收方接口,如何向多人发起分账
添加分账接收方的参数 receiver ,按照文档提示,只能填写一个接受账户,那如果要给多人分账, 是通过将receiver 定义为二维数组? 还是调用多次 添加分账接收方接口? 要分帐给多人需求如何实现?
2020-03-17 - .net 提交分账请求 【普通直连分账】
public void WxOpenProfit(string OrderID) { WeixinTrace.Log("\r\n\r\n----------------------------分账开始-----------------------------------------------\r\n\r\n"); Logger logger = LogManager.GetLogger("SimpleDemo"); string mch_id = Globals.Configuration["AppSettings:TenPayV3_MchId"].ToString(); string appid = Globals.Configuration["AppSettings:WxOpenAppId"].ToString(); string TenPayV3_Key = Globals.Configuration["AppSettings:TenPayV3_Key"].ToString(); string nonce_str = TenPayV3Util.GetNoncestr(); ShopOrder order = this.CreateService<IShopOrderService>().GetModel(OrderID); List<Shop_ShareOrder> share_list = this.CreateService<IShop_ShareService>().GetShopShareOrderList(OrderID); List<Receiver> receivers = new List<Receiver>(); Receiver receiver = null; foreach (var item in share_list) { if (item.Tag == "客户经理") { receiver = new Receiver(); receiver.account = item.Account; receiver.amount = Convert.ToInt32(item.ShareTotal * 100); receiver.description = item.OrderCode + "分账给客户经理:" + item.IDName; receiver.type = item.SortName; receivers.Add(receiver); } } string jsons = Newtonsoft.Json.JsonConvert.SerializeObject(receivers); logger.Info("\r\n\r\n*********************************分账表************************************\r\n\r\n"); logger.Info(jsons); var IPF = this.CreateService<IProfitService>(); Profit profitInfo = IPF.GetModelByOrderID(OrderID); //微信支付订单号 string transaction_id = profitInfo.wxTransactionID; //商户分账单号 string out_order_no = profitInfo.wxOutTradeNo; string stringA = "appid=" + appid + "&mch_id=" + mch_id + "&nonce_str=" + nonce_str + "&out_order_no=" + out_order_no + "&receivers=" + jsons + "&transaction_id=" + transaction_id; string stringSignTemp = stringA + "&key=" + TenPayV3_Key; //注:key为商户平台设置的密钥key+ string sign = EncryptHelper.GetHmacSha256(stringSignTemp, TenPayV3_Key).ToUpper(); Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("appid", appid); dic.Add("mch_id", mch_id); dic.Add("nonce_str", nonce_str); dic.Add("out_order_no", out_order_no); dic.Add("transaction_id", transaction_id); dic.Add("sign", sign); dic.Add("receivers", jsons); StringBuilder sb = new StringBuilder(); sb.Append("<xml>"); foreach (string k in dic.Keys) { string v = (string)dic[k]; sb.Append("<" + k + ">" + v + "</" + k + ">"); } sb.Append("</xml>"); string post_xml = sb.ToString(); logger.Info("\r\n\r\n*********************************发送数据************************************\r\n\r\n"); logger.Info(post_xml); string result = string.Empty; var handler = new HttpClientHandler(); X509Certificate2 certificate = GetMyX509Certificate(mch_id); logger.Info("\r\n\r\n*********************************证书************************************\r\n\r\n"); logger.Info(certificate.ToJson()); handler.ClientCertificateOptions = ClientCertificateOption.Manual; handler.SslProtocols = SslProtocols.Tls12; handler.ClientCertificates.Add(certificate); using (var httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml")); var content = new StringContent(post_xml); content.Headers.ContentType = new MediaTypeHeaderValue("application/xml"); var response = httpClient.PostAsync("https://api.mch.weixin.qq.com/secapi/pay/profitsharing", content).Result; result = response.Content.ReadAsStringAsync().Result; } logger.Info("\r\n\r\n*********************************返回数据************************************\r\n\r\n"); logger.Info(result); wxProfit return_profit = JsonConvert.DeserializeObject<wxProfit>(result); if (return_profit.return_code == "SUCCESS") { if (return_profit.result_code == "SUCCESS") { UpdateProfitInput update = new UpdateProfitInput(); update.Attach = profitInfo.Attach; update.CreateDate = profitInfo.CreateDate; update.Id = profitInfo.Id; update.OpenID = profitInfo.OpenID; update.OrderID = profitInfo.OrderID; update.ResultCode = return_profit.result_code; update.ReturnCode = return_profit.return_code; update.ShopID = profitInfo.ShopID; update.TimeEnd = DateTime.Now; update.WxOrderID = return_profit.order_id; update.wxOutTradeNo = profitInfo.wxOutTradeNo; update.wxTransactionID = profitInfo.wxTransactionID; update.ReMark = "ok"; IPF.Update(update); List<Profit_Item> profit_Items = new List<Profit_Item>(); Profit_Item profit_Item = null; foreach (var item in share_list) { profit_Item = new Profit_Item(); profit_Item.Account = item.Account; profit_Item.Amount = Convert.ToInt32(item.ShareTotal * 100); profit_Item.Id = ""; profit_Item.ProfitID = profitInfo.Id; profit_Item.Type = item.SortName; profit_Item.UserID = item.UserID; if (item.Tag == "客户经理") { profit_Item.Description = item.OrderCode + "自动分账给客户经理:" + item.IDName; } else { profit_Item.Description = item.OrderCode + "手动分账给商家:" + item.IDName; } profit_Items.Add(profit_Item); } this.CreateService<IProfit_ItemService>().BatchInsert(profit_Items);//保存分账列表 //return this.SuccessMsg("分账成功"); } else { UpdateProfitInput update = new UpdateProfitInput(); update.Attach = profitInfo.Attach; update.CreateDate = profitInfo.CreateDate; update.Id = profitInfo.Id; update.OpenID = profitInfo.OpenID; update.OrderID = profitInfo.OrderID; update.ResultCode = return_profit.result_code; update.ReturnCode = return_profit.return_code; update.ShopID = profitInfo.ShopID; update.TimeEnd = DateTime.Now; update.WxOrderID = ""; update.wxOutTradeNo = profitInfo.wxOutTradeNo; update.wxTransactionID = profitInfo.wxTransactionID; update.ReMark = return_profit.err_code + ":" + return_profit.err_code_des; IPF.Update(update); //return this.FailedMsg(); } } else { UpdateProfitInput update = new UpdateProfitInput(); update.Attach = profitInfo.Attach; update.CreateDate = profitInfo.CreateDate; update.Id = profitInfo.Id; update.OpenID = profitInfo.OpenID; update.OrderID = profitInfo.OrderID; update.ResultCode = ""; update.ReturnCode = return_profit.return_code; update.ShopID = profitInfo.ShopID; update.TimeEnd = DateTime.Now; update.WxOrderID = ""; update.wxOutTradeNo = profitInfo.wxOutTradeNo; update.wxTransactionID = profitInfo.wxTransactionID; update.ReMark = "通信错误"; IPF.Update(update); //return this.FailedMsg(); } logger.Info("\r\n\r\n----------------------分账结束-----------------------------------------------------------------\r\n\r\n"); }
2019-09-10 - 分账功能遇到问题及流程分享
自己先是遇到了调用分账功能的时候,提示SYSTEMERROR。 于是我开始排查之旅: 统一下单你不知道的(https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=9_1): 添加一个额外字段profit_sharing 设置值 Y 其它4个字段appid:服务商绑定的公众号的id;mch_id:服务商的微信支付商户号;sub_mch_id:服务商添加的子商户号;sub_appid:发起支付的小程序id 在服务商微信支付里面【服务商功能】>【特约商户管理】,点击对应子商户的配置,然后在【特约商户APPID配置】添加支付的小程序appid,其中这个app必须和子商户或者服务商是同一个运营主体 在使用分账之前,你必须把需要分账的账户现在添加到子商户里面,这个可以通过连接查看使用方法:https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_3&index=4 上面都成功之后,下来可以分账了:https://pay.weixin.qq.com/wiki/doc/api/allocation.php?chapter=27_1&index=1 其中分账时分账的对象金额不能为0,不然会出错 分账金额不能大于之前与子商户协商的最大分账比率 出现SYSTEMERROR,之前我这块时下单时直接下单给子商户了,没有设置sub_mch_id,sub_appid,只设置了profit_sharing,没有提示,就是在分账时出现SYSTEMERROR,并且没有描述。 微信文档这块,没有一个流程把需要设置配置哪些东西,什么时候有什么限制,所以我记录一下。
2019-08-21 - 微信支付接口报【签名错误】,看这一篇就够了
此文章致力解决在开发微信支付相关接口报【签名错误】,并不断升级更新 文章demo以’普通商户版’-‘JSAPI支付’作为案例(JSAPI支付文档) 先讲一下开发步骤和经验,文章后半部分讲排错经验 开发步骤 一 设置支付目录(文档链接) 支付目录,一定要设置实际支付页面的路径以 / 结尾,如果提示<当前页面URL未注册>,请检查自己实际支付页面的路径是否填写正确 发起支付的业务流程,我们做的操作应该是这样的:用户选择支付金额和其他参数–>用户点击支付–>前端向后台发起请求获取签名等参数–>后台调用统一下单接口,返回给前端需要的签名参数–>前端调用WeixinJSBridge.invoke–>用户填写密码–>支付成功–>微信发送通知给统一下单填写的回调方法。详细业务流程点我查看 二 后台调用统一下单接口(文档链接) 此接口参数非常多,第一次开发的时候,建议开发者仔仔细细对每个参数进行比对。遇到签名错误的同学,大部分人的原因是因为参数填写错误导致的 后台在给前端准备参数的时候,是要进行两次签名的:第一次是发送统一下单请求之前,对发送给微信的所有参数进行签名;第二次是微信返回预支付交易会话标识后,对传给前端的所有参数进行签名。 请注意,第一次签名和第二次签名的时候,参数是不一样的,第二次签名的时候,签名需要哪些参数呢?签名的参数是WeixinJSBridge.invoke需要用到的参数,和第一次签名需要的参数是不一样的! 对于参数package我第一次粗心大意,没有拼接字符串‘prepay_id=’希望大家也注意一些,前后台都需要拼接这个字符串‘prepay_id=’ 这是我刚刚花费10分钱获取的统一下单截图 [图片] 只有result_code和return_code都为SUCCESS的时候,说明调用成功,成功拿到预支付的id 三 前端获取参数后拉起微信支付(文档链接) [图片] 其实完整坐下来,微信支付就这么点东西,只是大家可能有些不熟悉,对于大家遇到的签名错误问题,绝大部分是参数没有认真进行参数比对,参数不能多,也不能少。如果还报错,建议从下面一些方式进行排查 排错经验 · 首先排查签名方法是否正确(签名效验工具),如果自己写的签名方法和工具展示出来的结果一模一样,说明你签名的工具方法写的没有问题,那么就剩下参数的问题了! · 然后进行参数比对,根据开发文档,进行比对,一个字母都不能差 · 第一次签名和第二次签名的APPID ,后台签名的i是小写,前端调用的是大写 · 后端第二次签名,参数package一定不要忘记拼接prepay_id · 请再三确认appid和mch_id是否正确,如果同时进行多个公众号支付开发,一定不要弄混 · 第二次签名参数timeStamp时间差距太大(你服务器时间要尽量准确,好像误差不能超过10分钟) · 中文参数错误,英文参数没有问题的,本文以MD5加密为例,请在加密的时候,指定编码格式为UTF-8 对于企业付款到零钱/银行卡 · 尝试在商户平台的账户信息中更改API密钥(账户设置-安全设置-API安全), 15分钟后生效 · 还是参数,参数,参数 终极杀器·缓存 作者开发语言是java,之前缓存无处不在,myeclipse(开发者工具)的缓存,本地编译缓存,服务器tomcat的缓存,如果你觉得我就是对的,什么都排查过了,没有问题,OK,建议清理缓存(先删除tomcat里边的项目,再添加然后重新编译项目;服务器tomcat缓存,清理tomcat文件夹下work-catalina文件夹的内容)。实在不行,重启本地电脑。重启服务器server。 请各位同学一定要先自行排查问题,如果还无法解决问题,或者你遇到过其他bug情况,欢迎留言,我会及时更新到文章,以便帮助更多人解决签名错误的问题。ღ( ´・ᴗ・` )比心 ------------------分割线------------------- 签名方式是否真的正确? ----------2019年12月2日更新,感谢斌斌反馈---------- 由于作者做支付是在2016年,辛辛苦苦整理了一份demo,一直沿用至今,忘记当时是否有官方sdk了,如果大家用的是官方sdkDemo,以上bug排查完,还是报签名错误,请检查签名方式,实际是MD5还是HMACSHA256。具体情况可以看这篇提问【JSAPI第二次签名到底什么机制?】
2021-03-18