收藏
回答

微信支付v3 jsapi调起支付时,支付验证签名失败?

/**html**/
/**
 *JSAPI支付
 **/
function onBridgeReady(result) {
    alert( result.appId );
    alert( result.timeStamp );
    alert( result.nonceStr );
    alert( result.package );
    alert( result.signType );
    alert( result.paySign );
    WeixinJSBridge.invoke('getBrandWCPayRequest', {
        "appId"    : result.appId,   //公众号ID,由商户传入
        "timeStamp": result.timeStamp,   //时间戳,自1970年以来的秒数
        "nonceStr" : result.nonceStr,      //随机串
        "package"  : result.package,
        "signType" : result.signType,     //微信签名方式:
        "paySign"  : result.paySign,  //微信签名
        },
    function (res) {
        alert( JSON.parse(res) );
        if (res.err_msg == "get_brand_wcpay_request:ok") {
            // 使用以上方式判断前端返回,微信团队郑重提示:
            //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
        }
    });
}


//****?

<?php
/**
 * WeChat pay
 * 库和SDK  wechatpay-guzzle-middleware
 * User:wang jian
 * Date:2021.12.24
 */
namespace App\Library;

use GuzzleHttp\Exception\RequestException;
use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
use WechatPay\GuzzleMiddleware\Util\PemUtil;
use GuzzleHttp\HandlerStack;

class WeChatTwo
{
    private  static $merchantId;                    //微信_商户号
    private  static $appid;                         //微信开放平台_appid
    private  static $appkey;                        //微信开放平台_appkey
    private  static $merchantCertificateSerial;     //微信_商户API证书序列号
    private  static $apiv3key;                      //微信_APIV3密钥
    private  static $merchantPrivateKeyFilePath;    //微信_商户API证书私钥
    private  static $platformCertificateFilePath;   //微信_支付平台证书_初始生成——其它加载
    private  static $upload_img_api;                //图片上传接APIurl
    private  static $client;

    public function __construct()
    {
        WeChatTwo::$merchantId  =  config('wechat.merchantId'); //微信_商户号
        WeChatTwo::$appid       =  config('wechat.appid');      //微信开放平台_appid
        WeChatTwo::$appkey      =  config('wechat.appkey');     //微信开放平台_appkey
        WeChatTwo::$apiv3key    =  config('wechat.apiv3key');   //微信开放平台_appkey
        WeChatTwo::$merchantCertificateSerial   =  config('wechat.merchantCertificateSerial'); //微信_商户API证书序列号
        WeChatTwo::$merchantPrivateKeyFilePath  = storage_path('cert'.DIRECTORY_SEPARATOR.'wechat'.DIRECTORY_SEPARATOR.'4C1BBE189365B735FF1B7AE9A63EDCB7CDA49093'.DIRECTORY_SEPARATOR.'apiclient_key.pem');//商户API证书私钥
        WeChatTwo::$platformCertificateFilePath = storage_path('cert'.DIRECTORY_SEPARATOR.'wechat'.DIRECTORY_SEPARATOR.'4C1BBE189365B735FF1B7AE9A63EDCB7CDA49093'.DIRECTORY_SEPARATOR.'wechatpay_67BD0BB346B4ABD494092F0F7FCF507A42E48A1E.pem');//微信_支付平台证书_初始生成——其它加载
        WeChatTwo::$upload_img_api              =  'https://api.mch.weixin.qq.com/v3/merchant/media/upload'; //图片上传接API url

        WeChatTwo::$client = WeChatTwo::instanceWeChatPay();
    }

    /**
     * 构建一个客户端实例
     * wechatpay-guzzle-middleware,适用于PHP开发者
     */
    public static function instanceWeChatPay(){
        // 商户相关配置,
        $merchantId = WeChatTwo::$merchantId; // 商户号
        $merchantSerialNumber = WeChatTwo::$merchantCertificateSerial; // 商户API证书序列号
        $merchantPrivateKey   = PemUtil::loadPrivateKey(WeChatTwo::$merchantPrivateKeyFilePath); // 商户私钥文件路径
        // 微信支付平台配置
        $wechatpayCertificate = PemUtil::loadCertificate(WeChatTwo::$platformCertificateFilePath); // 微信支付平台证书文件路径

        // 构造一个WechatPayMiddleware
        $wechatpayMiddleware  = WechatPayMiddleware::builder()
            ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 传入商户相关配置
            ->withWechatPay([ $wechatpayCertificate ]) // 可传入多个微信支付平台证书,参数类型为array
            ->build();
        // 将WechatPayMiddleware添加到Guzzle的HandlerStack中
        $stack =\GuzzleHttp\HandlerStack::create();
        $stack->push($wechatpayMiddleware, 'wechatpay');
        // 创建Guzzle HTTP Client时,将HandlerStack传入,接下来,正常使用Guzzle发起API请求,WechatPayMiddleware会自动地处理签名和验签
        //WeChatTwo::$client = new \GuzzleHttp\Client(['handler' => $stack]);
        return new \GuzzleHttp\Client(['handler' => $stack]);
    }

    /**
     *  JSAPI支付下单
     *  同步请求
     * @param $out_trade_no
     * @param $description
     * @param $total
     */
    public function JsapiSyncWeChatPay($total,$description,$notify_url,$out_trade_no,$openid,$attach ='')
    {
        $data = [];
        try {
            if(!$total || !$description || !$notify_url || !$out_trade_no || !$openid){
                $data['statusCode'] = 400;
                $data['msg']        = '缺少必要参数,稍后再试';
                return $data;
            }
            $time_expire    = date("Y-m-d\TH:i:s\Z",strtotime("30*60 seconds") );
            $order = [
                "time_expire" => $time_expire,                              //交易结束时间--订单失效时间
                "mchid"       => WeChatTwo::$merchantId,                    //直连商户号   Required
                "appid"       => WeChatTwo::$appid,                         //应用ID      Required
                "notify_url"  => $notify_url,                               //通知地址     Required
                "out_trade_no"=> $out_trade_no,                             //商户订单号    Required
                "amount"      => ["total" => $total,"currency" => "CNY"],   //订单金额信息  Required
                "description" => $description,                              //商品描述     Required
                "payer" => [
                    "openid" => $openid,                                    //获取微信用户的$openid
                ],
                //"attach"    => "自定义数据说明",                             //附加数据
            ];

            $timestamp  = time();
            $nonce      = WeChatTwo::getNonceStr();
            $url        ="https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
            $resp       = WeChatTwo::$client->request(
                'POST',
                $url, //请求URL
                [
                    // JSON请求体
                    'json' => $order,
                    'headers' => [
                        'Accept' => 'application/json',
                        'Authorization' => 'WECHATPAY2-SHA256-RSA2048'.WeChatTwo::SignatureGenerate ($url, "POST", "",$timestamp,$nonce),
                    ]
                ]
            );
            $statusCode = $resp->getStatusCode();
            if ($statusCode == 200) { //处理成功
                $getContents = json_decode($resp->getBody()->getContents());

                $body['appId']      = WeChatTwo::$appid;     //公众号ID,由商户传入
                $body['timeStamp']  = $timestamp;  //时间戳
                $body['nonceStr']   = $nonce;  //随机串
                $body['package']    = "prepay_id=" . $getContents->prepay_id;
                $body['signType']   = "RSA";     //微信签名方式:
                $body['paySign']    = WeChatTwo::paySign($url, "POST", $body['package'],$timestamp,$nonce); //微信签名

                $data['msg']        = '处理成功';
                $data['statusCode'] = 200;
                $data['body']       = $body;
            } else if ($statusCode == 204) { //处理成功,无返回Body
                $data['msg']        = '微信支付统一下单失败';//'处理成功,无返回Body,请刷新后再试';
                $data['statusCode'] = 204;
            }
            return $data;
        } catch (RequestException $e) {
            $data['msg']        = $e->getMessage();
            $data['statusCode'] = 400;
            return $data;
            /*// 进行错误处理
            echo $e->getMessage()."\n";
            if ($e->hasResponse()) {
                echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
            }*/
        }
    }

  

    /**
     * 生成签名
     * @param $appId
     * @param $timeStamp
     * @param $nonceStr
     * @param $package
     * @return string
     */
    public  static function paySign($url = "", $http_method = "POST",  $body = "", $timestamp = "", $nonce="")
    {
        if (!in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
            throw new RuntimeException("当前PHP环境不支持SHA256withRSA");
        }
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        //当前时间戳
        $timestamp =  empty($timestamp) ? time() : $timestamp;
        //随机字符串
        $nonce     = empty($nonce) ? WeChatTwo::getNonceStr() : $nonce;
        //POST请求时 需要 转JSON字符串
        $message = $http_method."\n".
            $canonical_url."\n".
            $timestamp."\n".
            $nonce."\n".
            $body."\n";

        //生成签名
        openssl_sign($message, $raw_sign, openssl_get_privatekey(file_get_contents( WeChatTwo::$merchantPrivateKeyFilePath )), 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);
        return $sign;
    }

    /**
     * 生成  Authorization
     * @param string $url
     * @param string $http_method
     * @param string $body
     * @return string
     */
    public static function SignatureGenerate ($url = "", $http_method = "POST",  $body = "", $timestamp = "", $nonce="")
    {
        //当前时间戳
        $timestamp  =  empty($timestamp) ? time() : $timestamp;
        //随机字符串
        $nonce      = empty($nonce) ? WeChatTwo::getNonceStr() : $nonce;
        $sign       = WeChatTwo::paySign($url, $http_method,  $body,$timestamp,$nonce);
        //$schema   = 'WECHATPAY2-SHA256-RSA2048'; ////Authorization 类型
        $token      = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',WeChatTwo::$merchantId, $nonce, $timestamp, WeChatTwo::$merchantCertificateSerial, $sign);
        return  $token;
    }

    // 解密数据
    public function decryptSign($ciphertext, $associatedData, $nonceStr)
    {
        $ciphertext = base64_decode($ciphertext);
        if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available()) {
            //$APIv3_KEY就是在商户平台后端设置是APIv3秘钥
            $orderData = \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, WeChatTwo::$apiv3key);
            $orderData = json_decode($orderData, true);
            return $orderData;
        }else{
            //exit('缺乏PHP扩展:sodium,请安装该扩展或切换到PHP7.3+版本');
        }

        return false;
    }

    /**将字符串安全编码
     *
     * @param  $string
     *
     * @return string
     */
    public function urlsafe_b64encode($string)
    {
        $data = base64_encode($string);
        $data = str_replace(array('+', '/', '='), array('-', '_', ''), $data);
        return $data;
    }

    /**将字符串安全解码
     *
     * @param  $string
     *
     * @return string
     */
    public function urlsafe_b64decode($string)
    {
        $data = str_replace(array('-', '_'), array('+', '/'), $string);
        $mod4 = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        return base64_decode($data);
    }

  

    /*
    * 产生随机字符串,不长于32位
    * @param int $length
    * @return string
    */
    public static function getNonceStr($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }


}

回答关注问题邀请回答
收藏

2 个回答

  • X
    X
    2022-02-18

    什么问题呀

    2022-02-18
    有用 1
    回复
  • 雅彤
    雅彤
    2021-12-31

    已解决

    2021-12-31
    有用
    回复 2
    • ㅤ
      2022-06-29
      咋搞的
      2022-06-29
      回复
    • 森林
      森林
      2022-09-13
      咋处理的
      2022-09-13
      回复
登录 后发表内容