微信支付V3版避坑之签名篇

1,101 阅读1分钟

前言

各位小伙伴们大家好啊,最近微信更新了微信支付V3版本。本人也是有幸接到了支付升级的任务,本篇将记录下计算签名的详细过程,以免大家看官方文档有点丈二和尚摸不着头脑。

废话不多说先上才艺

<?php

class Authorization
{
    public function get($url, $mch_id, $http_method, $body)
    {
        $nonce = md5(uniqid());
        $timestamp = time();
        $serial_no = env('WECHATPAY_V3_SERIAL_NO');
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $message = strtoupper($http_method) . "\n" .
            $canonical_url . "\n" .
            $timestamp . "\n" .
            $nonce . "\n" .
            $body . "\n";

        $path = storage_path('app/') . "CA/apiclient_key.pem";
        $mch_private_key = openssl_get_privatekey(file_get_contents($path));
        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);

        $schema = "WECHATPAY2-SHA256-RSA2048 ";
        $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $mch_id, $nonce, $timestamp, $serial_no, $sign);
        return $schema . $token;
    }
}

画重点

$url 请求的接口url
$mch_id 微信支付商户ID
$http_method 接口的请求方法 (!!!转换成大写!!!) 

$nonce = md5(uniqid()); 随机字符串
$timestamp = time(); 当前时间戳
$serial_no = env('WECHATPAY_V3_SERIAL_NO'); 图 1-1

图 1-1

拨云见雾

Authorization: <schema> <token>

Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1427527***",nonce_str="93de037816b32b828713a6b7b515ce07",timestamp="1597760164",serial_no="3C282195D6ADE6D6F821A984B36BF032D199***",signature="nbEiZgejeaAEWrzpES6RHzr5JG7Qqkt5gDXY6C9MJP2...jzvvuYwpgJrnWFIgOcA9zLi5/L+HLsQFqoIVaa50AqWoEvG49MSA5dZ7FF+rgL3FiYUQ=="

小试牛刀

# 获取证书
$auth = new Authorization();
$config = config("wechat-v3");
$mch_id = Arr::get($config, 'mch_id', 0);
$request_url = 'https://api.mch.weixin.qq.com/v3/certificates';
$authorization = $auth->get($request_url, $mch_id, "GET", '');

try{
    $client = new Client();
    $info = $client->request('get', $request_url, [
        'headers' => [
            'Authorization' => $authorization,
            'Content-type' => 'application/json',
            'Accept' => 'application/json'
        ]
    ]);
}catch (\GuzzleHttp\Exception\ClientException $exception){
    $response = $exception->getResponse()->getBody()->getContents();
    return json_decode($response, true);
}
return $info->getBody()->getContents();

# return
{
    "data": [
        {
            "effective_time": "2020-08-14T15:25:22+08:00",
            "encrypt_certificate": {
                "algorithm": "AEAD_AES_256_GCM",
                "associated_data": "certificate",
                "ciphertext": "1FuwEnWi3eJsXaDMVy5ECeaHQvLMyaA3HGcwoG*****",
                "nonce": "c43203286ed2"
            },
            "expire_time": "2025-08-13T15:25:22+08:00",
            "serial_no": "2C2E956394F3294651106ADBD27FF4FE5CB7****"
        }
    ]
}

结语

不识庐山真面目,只缘身在此山中。

代码写不下去的时候,适当地放松自己,找同事来看看,出去转一圈,兴许就能豁然开朗!