收藏
回答

服务端api 加密签名一直报 errcode: 40235 错误,请问是哪里出了问题?

之前提示 签名失败

{"errcode":40234,"errmsg":"invalid signature rid: 660bbf5d-42122766-7111a136"}

目前一直提示无效的加密

{"errcode":40235,"errmsg":"invalid encrypt rid: 660bbb51-3e9b99bb-5a26a227"}

目前感觉应该是签名通过了,但是加密不对,实在找不到问题,下面是所有相关代码,求大佬解答


这是加密的方法

public function getRequestParams($requestParams = [])
{
    $timestamp = time();
    $appid = get_setting('app_id');// 能拿到 appid
    $nonce = rtrim(base64_encode(random_bytes(16)), '=');
    $iv = random_bytes(12);


    $AES256GCM = [
        'sn' => '596f0ce97*************f25ad51ad',
        'key' => 'ZDdlNDBl******************YjdiZTYwNWQ=',
    ];

    $aad = $this->urlpath . "|" . $appid . "|" . $timestamp . "|" . $AES256GCM['sn'];

    $requestParams = array_merge($requestParams, [
        '_n' => $nonce,
        '_appid' => $appid,
        '_timestamp' => $timestamp,
    ]);
    $requestParams = json_encode($requestParams);

    $cipher = openssl_encrypt($requestParams, "aes-256-gcm", base64_decode($AES256GCM['key']), OPENSSL_RAW_DATA, $iv, $tag, $aad);

    $iv = base64_encode($iv);
    $data = base64_encode($cipher);
    $authTag = base64_encode($tag);

    $finalRequestParams = ["iv" => $iv, "data" => $data, "authtag" => $authTag];
      // 这里结果能正常的打印出来 
    return ['timestamp' => $timestamp, 'request_params' => json_encode($finalRequestParams)];
}


这是签名的方法

public function getSignureHeaders($requestParams)
{
    $RSAwithSHA256 = [
        'sn' => '7a01f48****************f09ee3',
        'private_key' => '-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAtcBZzC2x7hBMH/kWWn/XClEtGrzkgPyj2+CiCA0OogwAL6Q/
CSK2tahY3GFFIP/7zLd3OC16V4Gb93Hf+n9YDjjoExQgkEX06sBzwSwC8PFGAZPw
Jr5DEQGoKt64xydIkIAMHynNzltHInz7XD4fuJLxdi3CYitUd6pNATjax3a1OuO5
******************* 这里打一下码, 删除了很多行 *******************
liDw02EvRE3BWL3nqgEPt/PP1us+LUg3uOKOrOTD+w7hUPRaBIR41hz+9V+YszTs
oZk51Bq+/vZG7FoUXc7hB8cS9HANC2kOBU32Yf8fNWlpEMzg08N3yAw=
-----END RSA PRIVATE KEY-----'
    ];

    $appid = get_setting('app_id');  // 这里可以拿到 appid
    $rs_time = $requestParams['timestamp'];       // 上一步加密时候的时间戳
    $rs_data = $requestParams['request_params'];  // 上一步最终加密的数据

    $payload = "$this->urlpath\n$appid\n$rs_time\n$rs_data";

    // 使用phpseclib3\Crypt\RSA(phpseclib V3)版本生成签名
    $signature = RSA::loadPrivateKey($RSAwithSHA256['private_key'])
        ->withPadding(RSA::SIGNATURE_PSS)
        ->withHash('sha256')
        ->withMGFHash('sha256')
        ->sign($payload);
    $signature = base64_encode($signature);

    $checkLocalSig = $this->checkLocalSignature($requestParams, $signature);   // 这里验签是可以通过的
    if (!$checkLocalSig) {
        throw new EStoreException('本地验签错误');
    } 

    $headers['Wechatmp-Appid'] = $appid;
    $headers['Wechatmp-TimeStamp'] = $requestParams['timestamp'];
    $headers['Wechatmp-Signature'] = $signature;
    return $headers;
}

private function checkLocalSignature(array $requestParams, string $signature)
{
    $signature = base64_decode($signature);
    $rsaPubKey = '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtcBZzC2x7hBMH/kWWn/X
ClEtGrzkgPyj2+CiCA0OogwAL6Q/CSK2tahY3GFFIP/7zLd3OC16V4Gb93Hf+n9Y
******************* 这里打一下码 *******************
wLx6tzfnHvRz0vTf5KEoOvbk3UOUJ8xR/J753cHxh9MumN+4IUgoVF01ju64b95B
VQIDAQAB
-----END PUBLIC KEY-----';
    $appid = get_setting('app_id');  // 这里能拿到 appid
    $rs_time = $requestParams['timestamp'];       // 上一步加密时候的时间戳
    $rs_data = $requestParams['request_params'];  // 上一步最终加密的数据

    $payload = "$this->urlpath\n$appid\n$rs_time\n$rs_data";

    return RSA::loadPublicKey($rsaPubKey)
        ->withPadding(RSA::SIGNATURE_PSS)
        ->withHash('sha256')
        ->withMGFHash('sha256')
        ->verify($payload, $signature);
}


请求的方法

/**
 * 微信api 安全请求,自动加密数据,添加签名
 */
public function safeRequest($method = 'post', $url = '', $data = [])
{
    $body = $data['body'] ?? [];
    $query = $data['query'] ?? [];
    $headers = $data['headers'] ?? [];

    // 获取加密请求参数
    $apiSignure = new ApiSignure($url);     // 就是上面的方法的类名
    $resultParams = $apiSignure->getRequestParams($body);  // 上面的加密方法
    $newBody = $resultParams['request_params'];       //  加密的结果

    // 获取签名 headers 参数
    $signureHeaders = $apiSignure->getSignureHeaders($resultParams);  // 上面的签名方法

    $access_token = $this->getAccessToken();  // 获取 access_token 
    $result = \HttpClient::request($method, $url, [    // 这里用的是 guzzlehttp
        'body' => $newBody,
        'query' => array_merge(["access_token" => $access_token['access_token']], $query),
        'headers' => array_merge(['Content-Type' => 'application/json'], $headers, $signureHeaders),
    ]);

    print_r($result->getBody()->getContents());exit;
    return $result;
}


调用方法

// 查询 门店 接口
$url = 'https://api.weixin.qq.com/cgi-bin/express/intracity/querystore';

$result = $this->safeRequest('post', $url, [
    'body' => ['wx_store_id' => '400000*********4017'],  // id 打码了
]);



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

1 个回答

  • 安之若素~枫
    安之若素~枫
    04-10

    把你的 \HttpClient::request() 换成下面这个试试

    (new \GuzzleHttp\Client())->request("POST", $url, [    // 这里用的是 guzzlehttp
            'body' => $newBody,
            'query' => array_merge(["access_token" => $access_token['access_token']], $query),
            'headers' => array_merge(['Content-Type' => 'application/json'], $headers, $signureHeaders),
        ]
    );
    


    04-10
    有用
    回复 5
    • 小新
      小新
      04-15
      感谢老哥回复,不过这里应该可以排除了,我刚换了试了一下,我也用原生的 curl 请求试了一下,还是一样的错误
      04-15
      回复
    • 小新
      小新
      04-15
      有点崩溃,我把证书啥的全部重新换一下再试试
      04-15
      回复
    • 安之若素~枫
      安之若素~枫
      04-16回复小新
      你把相关参数(时间、随机字符串)固定住写死,然后用我那个扩展,对比一下每一步生成变量(加密字符串、秘钥啥的),看看我的和你的一不一样,看看这样能找出问题吗?
      04-16
      回复
    • 安之若素~枫
      安之若素~枫
      04-16回复小新
      或是私聊我一下,发一下你的加密请求文件,以及相关参数,我来试试
      04-16
      回复
    • --
      --
      04-28
      老哥能麻烦您帮我看看吗,我也一直在报错:40234。
      04-28
      回复
登录 后发表内容