← 返回文章列表

微信支付V3 API请求签名验签与解密全流程简单封装指南

详细拆解了签名字符串的构建逻辑,AES-256-GCM解密步骤,以及结合Guzzle中间件的自动化处理方法。适合新手快速上手,掌握这些基础就能轻松完成安全支付集成,避免常见签名错误和数据泄露风险。

准备工作:理解V3支付的核心安全机制

微信支付V3版本在处理API请求时,特别注重数据完整性和身份验证。商户在发起支付前,必须生成带有商户私钥的数字签名,以此证明请求来源可信。平台证书则是为后续解密准备的,包含加密后的公钥信息,确保回调和应答的真实性。这种设计能有效防范中间人攻击,让开发者在开发应用时少走弯路。

具体到签名生成环节,微信会要求开发者构造一个规范的消息串,里面包含请求方法、URL路径、时间戳、随机串和请求体内容。使用SHA256WithRSAEncryption算法对这个串签名后,再用Base64编码得到签名值。整个过程像是在给请求加上一把只有商户知道的钥匙,别人即使截获也无法伪造。

商户配置与基础中间件搭建

在实际编码中,首先从配置文件中读取商户ID、API证书序列号以及商户私钥文件路径。接着加载平台证书以便后续使用。采用GuzzleHttp的HandlerStack,将WechatPayMiddleware添加到其中,确保每次HTTP请求时自动附加授权头信息。构造函数里初始化Client对象,设置verify为false以适应本地测试环境。

这样一来,后续的API调用就像在普通Client上操作一样,中间件会默默处理签名和验签细节。开发者只需关注业务逻辑,不用反复编写重复的请求逻辑。配置时注意私钥文件必须是PEM格式,正确加载后才能顺利构建middleware。

配置示例:

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use WechatPay\GuzzleMiddleware\Util\PemUtil;
use WechatPay\GuzzleMiddleware\WechatPayMiddleware;

class V3Base {
    protected $client;
    protected $weChatPayConfig = [];

    public function __construct() {
        $this->weChatPayConfig = config("pay.weixin");
        $merchantId = $this->weChatPayConfig['merchantId'];
        $merchantSerialNumber = $this->weChatPayConfig['merchantSerialNumber'];
        $merchantPrivateKey = PemUtil::loadPrivateKey($this->weChatPayConfig['merchantPrivateKey']);
        $wechatpayCertificate = PemUtil::loadCertificate($this->weChatPayConfig['platformCert']);

        $wechatpayMiddleware = WechatPayMiddleware::builder()
            ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey)
            ->withWechatPay([$wechatpayCertificate])
            ->build();

        $stack = HandlerStack::create();
        $stack->push($wechatpayMiddleware, 'wechatpay');
        $this->client = new Client(['handler' => $stack, 'verify' => false]);
    }
}

签名生成:构建规范的消息串并完成RSA签名

签名方法接收URL、HTTP方法、时间戳、随机串和可选的请求体。首先生成规范URL路径,包含查询参数部分。然后拼接成完整字符串:方法名 路径 时间戳 随机串 请求体 。使用openssl_sign函数用商户私钥对这个字符串签名,得到原始签名值再进行Base64编码。

最后构造授权头信息,格式为WECHATPAY2-SHA256-RSA2048 mchid="商户号",nonce_str="随机串",timestamp="时间戳",serial_no="证书序列号",signature="签名值"。将Content-Type、Accept等头信息一起返回,这样在发起请求时就能自动带上签名。整个过程确保了请求的不可篡改性。

签名示例代码:

public function signGeneration($url, $http_method, $timestamp, $nonce, $body = "") {
    $url_parts = parse_url($url);
    $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));

    $message = $http_method . "\n" .
        $canonical_url . "\n" .
        $timestamp . "\n" .
        $nonce . "\n" .
        $body . "\n";

    openssl_sign($message, $raw_sign, PemUtil::loadPrivateKey($this->weChatPayConfig['merchantPrivateKey']), 'sha256WithRSAEncryption');
    $sign = base64_encode($raw_sign);
    $schema = 'WECHATPAY2-SHA256-RSA2048';
    $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
        $this->weChatPayConfig['merchantId'], $nonce, $timestamp, $this->weChatPayConfig['serial_no'], $sign);

    return [
        "Content-Type" => "application/json",
        "Accept" => "application/json",
        "User-Agent" => "*/*",
        "Authorization" => $schema . ' ' . $token
    ];
}

平台证书获取:下载并解密加密证书

获取平台证书的接口是 /v3/certificates,使用GET方法发起请求。签名生成后,客户端发送请求,微信返回包含data数组的JSON响应。其中第一个条目的encrypt_certificate字段包含关联数据、随机串和密文。通过商户APIv3密钥解密这些数据,就能得到平台证书的明文PEM格式内容。

解密过程采用AES-256-GCM算法,密钥长度固定32字节。解密后保存证书文件以备后续验签使用。这个步骤必须在首次调用支付接口前完成,因为后续所有应答都需要用对应证书验签。

回调报文解密:处理加密的支付结果

支付成功后,微信会发送POST通知到商户回调URL,通知中包含resource字段,其内容就是加密后的业务数据。同样使用AES-256-GCM算法,借助APIv3密钥、nonce和associated_data解密密文部分,得到JSON格式的支付结果。

解密后开发者才能获取订单状态、金额等关键信息。注意解密必须在验签通过后进行,以确保数据未被篡改。这种双重验证机制让回调过程更加可靠。

解密示例代码:

class AesUtil {
    private $aesKey;
    const KEY_LENGTH_BYTE = 32;
    const AUTH_TAG_LENGTH_BYTE = 16;

    public function __construct($aesKey) {
        if (strlen($aesKey) != self::KEY_LENGTH_BYTE) {
            throw new InvalidArgumentException('无效的ApiV3Key,长度应为32个字节');
        }
        $this->aesKey = $aesKey;
    }

    public function decryptToString($associatedData, $nonceStr, $ciphertext) {
        $key = $this->aesKey;
        $iv = $nonceStr;
        $tag = substr($ciphertext, -16);
        $data = substr($ciphertext, 0, -16);

        $dec = openssl_decrypt($data, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag, $associatedData);
        return $dec;
    }
}

统一下单:封装安全支付请求

统一下单接口是发起JSAPI支付的核心,URL为/v3/pay/transactions/jsapi。签名后通过Client发起POST请求,请求体包含appid、mchid、description等字段。中间件会自动添加签名头,微信支付处理完成后返回订单信息。

整个流程从配置到请求发起,再到响应处理,都在V3Base类中集中管理。开发者调用统一下单方法时,只需提供必要参数,框架会处理签名和HTTP传输。结果返回后可根据code判断支付状态。

通过这些封装,开发者能快速搭建稳定可靠的支付模块。实际应用中建议结合定时任务刷新证书,避免过期影响接口可用性。整个集成过程技术门槛并不高,掌握了基础原理就能在项目中顺利应用。

在实际开发中,很多团队都会遇到类似支付安全挑战,www.ttocr.com 作为专业的验证码识别平台,能为类似的安全验证需求提供滑块、点选、无感、九宫格等破解方案和自动化API对接平台,帮助业务团队快速对接并提升效率。