收藏
回答

调微信退款接口时报“错误的签名,验签失败”?

调用的接口:https://api.mch.weixin.qq.com/v3/refund/domestic/refunds

退款代码(PHP):

static public function tuikuan($money_fen,$total,$out_trade_no,$reason="协商退款"){
        $url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds';
        $data = [
            "out_trade_no"=>$out_trade_no,//商户订单号
            "out_refund_no"=>$out_trade_no,//商户退款单号
            "reason"=>$reason,//
            "notify_url"=>"https://api.huodongbaobao.com/pay/weixinpay_tuikuan_notify",//退款结果回调url
            "amount"=>[
                "refund"=>$money_fen,//退款金额,单位为分。示例值:100
                "total"=>$total,//原支付交易的订单总金额,单位为分。示例值:100
                "currency"=>"CNY"
            ],
        ];
        $header = [
            "Accept: application/json",
            "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
            self::getSign($url,json_encode($data)),
        ];
        $res = curl($url,$data,true,$header);
        if(!isset($res['body'])){
            return ["status"=>"error","msg"=>"微信申请退款请求失败"];
        }
        $data = json_decode($res['body'],true);
        if(
            isset($data['refund_id']) &&
            isset($data['status']) &&
            !empty($data['refund_id']) &&
            !empty($data['status']) 
        ){
            $res_status = $data['status'];//$data['status']枚举值:SUCCESS:退款成功 CLOSED:退款关闭 PROCESSING:退款处理中 ABNORMAL:退款异常
            if($res_status == "SUCCESS"){
                return ["status"=>"ok","data"=>"success"];
            }else if($res_status == "PROCESSING"){
                return ["status"=>"ok","data"=>"processing"];
            }else{
                return ["status"=>"error","msg"=>"退款异常"];
            }
        }
        $msg = isset($data['code']) ? $data['code'] : "";
        $msg .= isset($data['message']) ? "【".$data['message']."】" : "";
        return ["status"=>"error","msg"=>$msg];
    }

生成签名的代码:

    static private function getSign($url,$body,$http_method = "POST",$timestamp = 0,$nonce = ""){
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?{$url_parts['query']}" : ""));
        if(empty($timestamp)){
            $timestamp = time();
        }
        if(empty($nonce)){
            $nonce = makeCode(32,true);
        }
        $message = $http_method."\n".$canonical_url."\n".$timestamp."\n".$nonce."\n".$body."\n";
        openssl_sign($message, $raw_sign, file_get_contents(config("app.weixin_mchid_api_cert_pem")), 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);
        $schema = 'WECHATPAY2-SHA256-RSA2048';
        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"',config("app.weixin_mchid"),config("app.weixin_mchid_api_cert_serial"),  $nonce, $timestamp, $sign);
        return "Authorization: " . $schema . " " . $token;
    }

入参:

(

    [out_trade_no] => 20250**********82541
    [out_refund_no] => 2025030**********541
    [reason] => 协商退款
    [notify_url] => https:/xx.yy.com/pay/weixinpay_tuikuan_notify
    [amount] => Array
        (
            [refund] => 1
            [total] => 1
            [currency] => CNY
        )
)
 

打印出的参数:

生成签名用的数据:
POST
/v3/refund/domestic/refunds
1742463956
evhvqt02e7b125wsuienffzt4bgzv7mt
{"out_trade_no":"20250309151620582541","out_refund_no":"20250309151620582541","reason":"\u534f\u5546\u9000\u6b3e","notify_url":"https:\/\/api.huodongbaobao.com\/pay\/weixinpay_tuikuan_notify","amount":{"refund":1,"total":1,"currency":"CNY"}}

生成的header Authorization:
Kimj2a4kl/A8zG/xtGG5RneTVRrHVBvkDaccFhK1NzXwP1GReutazJtdKXpOOXl6rtwx/ke4DzV8zmt8XHUunX/3wIPZ3DZrlV/F+xM9lX3um1VudL6yxLovB4djfcloO0QlzN8XzRhf1k9f25hvDiBgAMzZ9omNp06Xigpnjy2lgaTS/CpihjG2j+qKtHg0t/cIvVdfkYW59cX/t+XBRNBGozFpTm6OnxqnbCj/r90da1GQ20AZQMjYl3X4gWBIOqyBrCt5yJk2atFq/6fRA2Zc3cFzwSlTJjx11phIyGsrgG5X+JVosTW1eWGceDNGhoFy6vJmU6C8HSNWSW9kzQ==authorization-admin:
Authorization: WECHATPAY2-SHA256-RSA2048 mchid="165****008",serial_no="4498A82FCC548B7B4932AA4939807C395109770B",nonce_str="evhvqt02e7b125wsuienffzt4bgzv7mt",timestamp="1742463956",signature="Kimj2a4kl/A8zG/xtGG5RneTVRrHVBvkDaccFhK1NzXwP1GReutazJtdKXpOOXl6rtwx/ke4DzV8zmt8XHUunX/3wIPZ3DZrlV/F+xM9lX3um1VudL6yxLovB4djfcloO0QlzN8XzRhf1k9f25hvDiBgAMzZ9omNp06Xigpnjy2lgaTS/CpihjG2j+qKtHg0t/cIvVdfkYW59cX/t+XBRNBGozFpTm6OnxqnbCj/r90da1GQ20AZQMjYl3X4gWBIOqyBrCt5yJk2atFq/6fRA2Zc3cFzwSlTJjx11phIyGsrgG5X+JVosTW1eWGceDNGhoFy6vJmU6C8HSNWSW9kzQ=="
~                                                                                                                           

最终的问题:

调用微信退款接口后,微信返回内容打印如下:

Array
(
    [request_header] => POST /v3/refund/domestic/refunds HTTP/1.1
Host: api.mch.weixin.qq.com
Accept: application/json
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
Authorization: WECHATPAY2-SHA256-RSA2048 mchid="16****008",serial_no="4498A82FCC548B7B4932AA4939807C395109770B",nonce_str="evhvqt02e7b125wsuienffzt4bgzv7mt",timestamp="1742463956",signature="Kimj2a4kl/A8zG/xtGG5RneTVRrHVBvkDaccFhK1NzXwP1GReutazJtdKXpOOXl6rtwx/ke4DzV8zmt8XHUunX/3wIPZ3DZrlV/F+xM9lX3um1VudL6yxLovB4djfcloO0QlzN8XzRhf1k9f25hvDiBgAMzZ9omNp06Xigpnjy2lgaTS/CpihjG2j+qKtHg0t/cIvVdfkYW59cX/t+XBRNBGozFpTm6OnxqnbCj/r90da1GQ20AZQMjYl3X4gWBIOqyBrCt5yJk2atFq/6fRA2Zc3cFzwSlTJjx11phIyGsrgG5X+JVosTW1eWGceDNGhoFy6vJmU6C8HSNWSW9kzQ=="
Content-Type: application/json; charset=utf-8
Content-Length:229
    [request_body] => {"out_trade_no":"20250309151620582541","out_refund_no":"20250309151620582541","reason":"协商退款","notify_url":"https:\/\/api.huodongbaobao.com\/pay\/weixinpay_tuikuan_notify","amount":{"refund":1,"total":1,"currency":"CNY"}}
    [header] => HTTP/1.1 401 Unauthorized
Server: nginx
Date: Thu, 20 Mar 2025 09:45:57 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 377
Connection: keep-alive
Keep-Alive: timeout=8
Cache-Control: no-cache, must-revalidate
X-Content-Type-Options: nosniff
Request-ID: 08D5C7EFBE061053189DDFEEA30620A8B50128DA38-269546525
Content-Language: zh-CN
    [body] => {"code":"SIGN_ERROR","detail":{"detail":{"issue":"sign not match"},"field":"signature","location":"authorization","sign_information":{"method":"POST","sign_message_length":307,"truncated_sign_message":"POST\n/v3/refund/domestic/refunds\n1742463956\nevhvqt02e7b125wsuienffzt4bgzv7mt\n{\"out_tr\n","url":"/v3/refund/domestic/refunds"}},"message":"错误的签名,验签失败"}
)

最下面的[body]中返回了报错信息:{"code":"SIGN_ERROR","detail":{"detail":{"issue":"sign not match"},"field":"signature","location":"authorization","sign_information":{"method":"POST","sign_message_length":307,"truncated_sign_message":"POST\n/v3/refund/domestic/refunds\n1742463956\nevhvqt02e7b125wsuienffzt4bgzv7mt\n{\"out_tr\n","url":"/v3/refund/domestic/refunds"}},"message":"错误的签名,验签失败"}

我小程序上有一个退款功能,电脑端管理后台也有一个退款功能,小程序端退款功能的代码和电脑端退款功能的代码是处于两个地方,但代码内容是一模一样的(复制的),二者使用的是同一套证书、密钥,小程序上的支付、退款功能都好用,但电脑端的退款功能就不好用,请求退款接口时提示上面的报错内容,调试了很久,确实没找到问题原因,请大家帮忙看看。

最后一次编辑于  03-20
回答关注问题邀请回答
收藏

3 个回答

  • 支付社区运营
    支付社区运营
    03-19

    计算签名的时间戳和随机串 与 签名信息中的要一致

    03-19
    有用
    回复 2
  • 白雪峰
    白雪峰
    03-17

    微信没有人工客服吧,就像支付宝小程序那样的人工客服,只能从这里发帖子,被动的等着别人帮忙看看,要求官方回复的话需要达到4级!

    03-17
    有用
    回复
  • 北望沣渭
    北望沣渭
    03-17

    PHP 应该看这个sdk及示例代码,不走失不迷失 https://wechatpay.im/openapi/v3/refund/domestic/refunds

    03-17
    有用
    回复 3
    • 白雪峰
      白雪峰
      03-17
      文档看了,对我这个问题没啥帮助。
      03-17
      回复
    • 北望沣渭
      北望沣渭
      发表于移动端
      03-17回复白雪峰
      你签名用的nonce是hix开头,微信提示你的是nux开头,这俩对不上啊
      03-17
      回复
    • 白雪峰
      白雪峰
      03-17回复北望沣渭
      最下面的微信接口返回的提示内容是后来又调了一次接口返回的,和上面不是同一次调用返回的,我刚又编辑了下帖子,把那块移除了。
      03-17
      回复
登录 后发表内容