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

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

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
    关注

    引自免费微信小程序:皆我百晓生

    根据您提供的错误信息,看起来是您的ASP.NET应用在调用微信支付API V3时遇到了签名验证失败的问题。微信支付要求开发者对请求参数进行特定的签名算法处理,然后将这个签名放在HTTP头中的Authorization字段。微信服务器会重新计算签名并验证它是否与发送的一致。如果验证不通过,就会返回上述错误。

    为了解决这个问题,首先我们需要确保所有传递给微信的参数都是正确的,并且按照指定的顺序排序。其次,我们需要正确地生成签名字符串并对其进行SHA256哈希。以下是详细的步骤:

    1. 整理请求参数:

      • 将所有的POST数据转换为JSON格式(如果有其他GET参数,也需要加入)。
      • 对所有参数按字典序排序(包括键值对的键和值)。
    2. 拼接签名字符串:

      • 将排序后的参数名、等号、参数值依次连接,中间无空格。
      • 在参数字符串末尾添加APPSECRET(注意:这里不是APPID)。
    3. 生成签名:

      • 使用SHA256哈希算法对签名字符串进行加密,得到一个二进制结果。
      • 将二进制结果转换为十六进制字符串。
    4. 设置HTTP头:

      • 将生成的签名字符串作为Authorization字段的值,格式为:Bearer [your_signature]

    接下来是一个示例代码,展示了如何在C# ASP.NET中实现这些步骤:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Security.Cryptography;
    using Newtonsoft.Json;
    
    public static string GenerateSignature(string appId, string appSecret, Dictionary<string, object> postData)
    {
        // 1. 整理请求参数
        var parameters = new SortedDictionary<string, string>();
        foreach (var kvp in postData)
        {
            parameters.Add(kvp.Key, kvp.Value.ToString());
        }
    
        // 2. 拼接签名字符串
        var signatureBaseString = string.Join("&", parameters.Select(p => $"{Uri.EscapeDataString(p.Key)}={Uri.EscapeDataString(p.Value)}"));
    
        // 3. 生成签名
        using (var sha256 = SHA256.Create())
        {
            var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(signatureBaseString));
            var signature = Convert.ToHexString(hashBytes);
            return $"Bearer {signature}";
        }
    }
    
    // 示例:调用微信API
    public async Task CallWeChatApiAsync()
    {
        const string appId = "your_app_id";
        const string appSecret = "your_app_secret";
        var postData = new Dictionary<string, object>
        {
            {"appid", "1717809045"},
            // 添加其他参数...
        };
    
        var signature = GenerateSignature(appId, appSecret, postData);
    
        using (var httpClient = new HttpClient())
        {
            httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Authorization", signature);
            var response = await httpClient.PostAsync("https://api.mch.weixin.qq.com/v3/transfer/batches", new FormUrlEncodedContent(postData));
    
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine($"Error: {response.StatusCode}");
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                Console.WriteLine(content);
            }
        }
    }
    

    请确保替换上述代码中的your_app_idyour_app_secret为实际的AppID和AppSecret。同时检查是否有遗漏的参数或排序错误。如果问题仍然存在,可能需要进一步排查请求数据和签名过程中的细节。

    评论 编辑记录

报告相同问题?

问题事件

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

悬赏问题

  • ¥15 is not in the mmseg::model registry。报错,模型注册表找不到自定义模块。
  • ¥15 安装quartus II18.1时弹出此error,怎么解决?
  • ¥15 keil官网下载psn序列号在哪
  • ¥15 想用adb命令做一个通话软件,播放录音
  • ¥30 Pytorch深度学习服务器跑不通问题解决?
  • ¥15 部分客户订单定位有误的问题
  • ¥15 如何在maya程序中利用python编写领子和褶裥的模型的方法
  • ¥15 Bug traq 数据包 大概什么价
  • ¥15 在anaconda上pytorch和paddle paddle下载报错
  • ¥25 自动填写QQ腾讯文档收集表