收藏
回答

小程序开启了服务端 API 签名加密,调用获取不限制的小程序码,一直报 40234 ?

public static function encryptedRequest($url, $params, $method = 'POST')
{
    self::init();
    $config = self::$config;

    // 解析URL获取不带query的路径用于加密
    $parsedUrl = parse_url($url);
    $urlPath = $parsedUrl['scheme'] . '://' . $parsedUrl['host'] . $parsedUrl['path'];

    // 1. 加密请求参数
    $encryptionData = self::getRequestParam($urlPath, $params);
    $timestamp = $encryptionData['timestamp'];

    // 2. 生成签名(根据微信文档,签名时 postdata 使用 req_data 即加密后的 JSON)
    $reqData = $encryptionData['reqData'];  // 加密后的 JSON 字符串
    $signature = self::getSignature($urlPath, $timestamp, $reqData);

    // 3. 构建请求体(发送时使用 req_ts + req_data 格式)
    $requestBody = json_encode([
        'req_ts' => $timestamp,
        'req_data' => $reqData,
    ], JSON_UNESCAPED_SLASHES);

    // 4. 构建请求头
    $headers = [
        'Content-Type: application/json',
        'Wechatmp-Appid: ' . $config['appid'],
        'Wechatmp-TimeStamp: ' . $timestamp,
        'Wechatmp-Signature: ' . $signature,
    ];

    // 5. 发送请求
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);

    if ($method === 'POST') {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
    }

    $response = curl_exec($ch);
    if ($response === false) {
        $error = curl_error($ch);
        curl_close($ch);
        throw new Exception('请求失败: ' . $error);
    }

    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    curl_close($ch);

    // 6. 解析响应头和响应体
    $headerStr = substr($response, 0, $headerSize);
    $body = substr($response, $headerSize);

    $responseHeaders = self::parseHeaders($headerStr);
    $responseData = json_decode($body, true);

    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new Exception('响应解析失败: ' . $body);
    }

    // 7. 检查是否为加密响应
    if (isset($responseData['iv']) && isset($responseData['data']) && isset($responseData['authtag'])) {
        // 验签
        $isValid = self::verifySign($urlPath, $responseHeaders, $body);
        if (!$isValid) {
            throw new Exception('响应签名验证失败');
        }

        // 解密
        $ts = $responseHeaders['Wechatmp-TimeStamp'] ?? time();
        return self::decryptToString($urlPath, $ts, $responseData);
    }

    // 非加密响应直接返回
    return $responseData;
}
public static function getRequestParam($url, $req)
{
    self::init();
    $config = self::$config;
    $time = time();
    $nonce = str_replace('=', '', base64_encode(random_bytes(16)));
    $addReq = ["_n" => $nonce, "_appid" => $config['appid'], "_timestamp" => $time]; // 添加字段
    $realReq = array_merge($addReq, $req);
    $plaintext = json_encode($realReq);
    //额外参数
    $message = $url . "|" . $config['appid'] . "|" . $time . "|" . $config['aes_sn'];
    $aesKey = base64_decode($config['aes_key']);
    $iv = random_bytes(12); // 12位随机字符
    $tag = '';
    // 数据加密处理
    $cipher = openssl_encrypt($plaintext, "aes-256-gcm", $aesKey, OPENSSL_RAW_DATA, $iv, $tag, $message);
    if ($cipher === false) {
        throw new Exception("Encryption failed: " . openssl_error_string());
    }
    $iv = base64_encode($iv);
    $data = base64_encode($cipher);
    $authTag = base64_encode($tag);
    $reqData = ["iv" => $iv, "data" => $data, "authtag" => $authTag];
    return ['timestamp' => $time, 'reqData' => json_encode($reqData)];
}
public static function getSignature($url, $timestamp, $postData)
{
    self::init();
    $config = self::$config;
    // 签名格式:urlpath\nappid\ntimestamp\npostdata
    $payload = $url . "\n" . $config["appid"] . "\n" . $timestamp . "\n" . $postData;
    $rsa = RSA::loadPrivateKey($config['private_key']);
    // 微信要求:PSS填充方式,salt长度为32(与SHA256结果长度一致)
    $rsa = $rsa->withPadding(RSA::SIGNATURE_PSS)
        ->withHash('sha256')
        ->withMGFHash('sha256')
        ->withSaltLength(32);
    $signature = $rsa->sign($payload);
    return base64_encode($signature);
}
$url    = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={$accessToken}";
$params = [
    'scene'      => $scene,
    'check_path' => false
];
$result = Wechat::encryptedRequest($url, $params);
var_dump($result);


输出:{ ["errcode"]=> int(40234) ["errmsg"]=> string(49) "invalid signature rid: 69787ed6-77fb24e3-01ef1aef" }


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

1 个回答

  • 智能回答 智能回答 本次回答由AI生成
    01-27
    有用
    回复
登录 后发表内容