xuxubaby 2024-06-08 09:31 采纳率: 0%
浏览 730
已结题

微信支付:错误的签名,验签失败

asp.net 有偿求解决微信APIV3验签错误问题。
排查了很多遍了没找到原因,求指导,谢谢。
是asp.net开发语言,不要从别处copy代码过来回复。
不要回复Java的代码,谢谢。

{
    "code": "SIGN_ERROR",
    "detail": {
        "detail": {
            "issue": "sign not match"
        },
        "field": "signature",
        "location": "authorization",
        "sign_information": {
            "method": "POST",
            "sign_message_length": 391,
            "truncated_sign_message": "POST\n/v3/transfer/batches\n1717809045\ne88f817a05b245fd870a5e1b827d3ebb\n{\"appid\"\n",
            "url": "/v3/transfer/batches"
        }
    },
    "message": "错误的签名,验签失败"
}

 public string tixian(string uid, int amount)
        {
            //商户平台证书号
            string zsh = "66CF9B00B8F357F29BFD1DFAAAAAAAAAAA";
            //证书密码(商户号)      
            string password = "1652555555";
            //请求地址
            string url = "https://api.mch.weixin.qq.com/v3/transfer/batches";
            //生成随机id
            var sn = "P" + IdHelper.GetId();
            string appid = "wxab7919b2axxxxx";
            string openid = uid;
            string batch_name = "提现";
            string batch_remark = "提现";
            int total_amount = amount;
            int total_num = 1;
            var transfer_detail_list = new List<Dictionary<string, object>>
            {
                new Dictionary<string, object> {
                ["out_detail_no"] = "T" + IdHelper.GetId(),
                ["transfer_amount"] = total_amount,
                ["transfer_remark"] = "提现",
                ["openid"] = openid,
                }
            };
            var parm = new Dictionary<string, object>
            {
                ["appid"] = appid,
                ["out_batch_no"] = sn,
                ["batch_name"] = batch_name,
                ["batch_remark"] = batch_remark,
                ["total_amount"] = total_amount,
                ["total_num"] = total_num,
                ["transfer_detail_list"] = transfer_detail_list,
            };
            //导出证书密钥
            string strReadFilePath = GlobalSwitch.WebRootPath + @"\apiclient_key.pem";
            LogHelper.WriteLog_LocalTxt(strReadFilePath);
            StreamReader srReadFile = new StreamReader(strReadFilePath, Encoding.GetEncoding("GB2312"));
            var txt = "";
            // 读取流直至文件末尾结束
            while (!srReadFile.EndOfStream)
            {
                string strReadLine = srReadFile.ReadLine(); //读取每行数据
                txt += strReadLine;
                Console.WriteLine(strReadLine); //屏幕打印每行数据
            }
            srReadFile.Close();


            LogHelper.WriteLog_LocalTxt("parmToJson:" + parm.ToJson());

            //发送post请求
            var sess = httpPost(url, parm.ToJson(), txt, password, zsh);

            LogHelper.WriteLog_LocalTxt("PayApi-tixian:" + sess);

            return "成功";
        }
        public static string httpPost(string url, string postData, string privateKey, string merchantId, string serialNo)
        {
            privateKey = privateKey.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "");
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "POST";
            request.ContentType = "application/json;charset=UTF-8";
            request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36";
            request.Accept = "application/json";

            //生成微信支付V3签名
            string Authorization = GetAuthorization(url, "POST", postData, privateKey, merchantId, serialNo);
            request.Headers.Add("Authorization", Authorization);
            byte[] paramJsonBytes = Encoding.UTF8.GetBytes(postData);
            request.ContentLength = paramJsonBytes.Length;
            Stream writer;
            try
            {
                writer = request.GetRequestStream();
            }
            catch (Exception)
            {
                writer = null;
                //throw new PayServiceException(500, "连接服务器失败");自定义异常类,无需理会
            }
            writer.Write(paramJsonBytes, 0, paramJsonBytes.Length);
            writer.Close();
            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                response = ex.Response as HttpWebResponse;
            }
            Stream resStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(resStream);
            string text = reader.ReadToEnd();
            LogHelper.WriteLog_LocalTxt("PostResult:" + text);
            //如果不是返回正确的响应,就把微信返回的message抛出去
            if (!response.StatusCode.ToString().Equals("OK"))
            {
                LogHelper.WriteLog_LocalTxt("PayApi-httpPost:" + text);
            }
            return text;
        }
        public static string GetAuthorization(string url, string method, string data, string privateKey, string merchantId, string serialNo)
        {
            var uri = new Uri(url);
            string urlPath = uri.PathAndQuery;
            //string urlPath = "/v3/certificates";
            string nonce = Guid.NewGuid().ToString("N");
            var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
            //数据签名     HTTP请求方法\n接口地址的url\n请求时间戳\n请求随机串\n请求报文主体\n
            method = string.IsNullOrEmpty(method) ? "" : method;
            //string message = string.Format("{0}\n{1}\n{2}\n{3}\n{4}", method, urlPath, timestamp, nonce, data);
            string message = $"{method}\n{uri}\n{timestamp}\n{nonce}\n{data}\n";
            LogHelper.WriteLog_LocalTxt("GetAuthorization-Message:" + message);
            LogHelper.WriteLog_LocalTxt("SignLength:" + message.Length);
            string signTxt = Sign(message, privateKey);
            //Authorization和格式
            string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"",
                merchantId,
                nonce,
                timestamp,
                serialNo,
                signTxt
                );
            LogHelper.WriteLog_LocalTxt("authorzationTxt:" + authorzationTxt);
            LogHelper.WriteLog_LocalTxt("signTxt:" + signTxt);
            return authorzationTxt;
        }
        public static string Sign(string message, string privateKey)
        {
            //string mes = message.ToJson();
            byte[] keyData = Convert.FromBase64String(privateKey);
            using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
            using (RSACng rsa = new RSACng(cngKey))
            {
                byte[] data = Encoding.UTF8.GetBytes(message);
                return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
            }
        }


+v:y00100594131

  • 写回答

22条回答 默认 最新

  • 阿里嘎多学长 2024-06-08 09:31
    关注

    以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


    遇到微信API V3的验签错误问题时,通常需要检查以下几个方面:

    1. 签名串的格式:确保签名串的构造是正确的,包括请求方法、URL、时间戳、随机字符串等,并且按照正确的顺序排列。
    2. 签名的生成:使用正确的私钥和算法生成签名。
    3. 请求参数的一致性:确保请求中的参数与签名时使用的参数完全一致。
    4. 编码问题:检查是否有编码不一致的问题,通常需要使用UTF-8编码。
    5. HTTP头的处理:确保HTTP头在传输过程中没有被修改或丢失。

    根据你提供的错误信息,这里有几个可能的原因和解决方案:

    • 签名串的换行符:确保签名串的最后一行有附加的换行符。如果请求报文主体为空(如GET请求),则需要特别注意这一点。[^1^][^5^]
    • 参数不一致:检查签名串中的参数是否与实际请求的参数一致。如果手工拼接URL,需要确保与实际请求发送的一致。[^1^]
    • 时间戳和随机字符串:确保签名和设置 Authorization 头时,使用的是同一个时间戳和随机字符串。[^1^]
    • 编码问题:生成签名串时,确保使用了UTF-8编码,并且没有设置错误的编码。[^1^]
    • 私钥和证书匹配:使用 openssl 命令检查私钥和商户证书中的modulus是否一致,以确保使用的是正确的私钥。[^1^]
    • 代理服务器或CDN配置:如果使用代理服务器或CDN,确保它们没有过滤微信支付扩展的HTTP头。[^1^][^5^]

    对于代码实现,可以参考以下伪代码来生成和验证签名:

    // 生成签名
    string message = $"{timestamp}\n{nonce}\n{body}\n";
    byte[] data = Encoding.UTF8.GetBytes(message);
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    rsa.ImportParameters(/* 私钥参数 */);
    string signature = Convert.ToBase64String(rsa.SignData(data, "SHA256"));
    
    // 验证签名
    rsa.ImportParameters(/* 公钥参数 */);
    bool isOk = rsa.VerifyData(data, "SHA256", Convert.FromBase64String(signature));
    

    相关的参考资料包括微信支付官方文档和开发者社区讨论,以下是部分链接:

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 6月11日
  • 修改了问题 6月9日
  • 修改了问题 6月9日
  • 修改了问题 6月9日
  • 展开全部