dongrouli2667 2015-07-21 10:06
浏览 50
已采纳

Google存储区的签名网址与提供的签名不符

I'm having an hard time working with google storage.

So I'm trying to make a signed url, already have the client id (which is an email) and private key (as described here) so:

STEP 1: construct the string

function googleBuildConfigurationString($method, $expiration, $file, array $options = []) {
    $allowedMethods = ['GET', 'HEAD', 'PUT', 'DELETE'];

    // initialize
    $method = strtoupper($method);
    $contentType = $options['Content_Type'];
    $contentMd5 = $options['Content_MD5'] ? base64_encode($options['Content_MD5']) : '';
    $headers = $options['Canonicalized_Extension_Headers'] ? $options['Canonicalized_Extension_Headers'] . PHP_EOL  : '';
    $file = $file ? $file : $options['Canonicalized_Resource'];

    // validate
    if(array_search($method, $allowedMethods) === false) {
        throw new RuntimeException("Method '{$method}' is not allowed");
    }
    if(!$expiration) {
        throw new RuntimeException("An expiration date should be provided.");
    }

    return <<<TXT
    {$method}
    {$contentMd5}
    {$contentType}
    {$expiration}
    {$headers}{$file}
    TXT;
}

So far so good (I think), echoing the output it looks similar to the examples, so now to sign the string

STEP 2: signing the string Initialy I was using openssl_public_encrypt, after searching around found that google-api-php-client has the Google_Signer_P12 (which actually uses openssl_sign), so the method looks like:

function googleSignString($certificatePath, $stringToSign) {
    return (new Google_Signer_P12(
        file_get_contents($certificatePath), 
        'notasecret'
    ))->sign($stringToSign);
}

And here I'm not sure if this is signing it correctly, finally building final url

STEP 3: building the URL

function googleBuildSignedUrl($serviceEmail, $file, $expiration, $signature) {
    return "http://storage.googleapis.com{$file}"
    . "?GoogleAccessId={$serviceEmail}"
    . "&Expires={$expiration}"
    . "&Signature=" . urlencode($signature);
}

But the opening the URL in the browser will retrieve:

<Error>
    <Code>SignatureDoesNotMatch</Code>
    <Message>
        The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.
    </Message>
    <StringToSign>GET 1437470250 /example/video.mp4</StringToSign>
</Error>

I've added a gist with the final script to be easier to read

So any idea what am I doing wrong?

  • 写回答

1条回答 默认 最新

  • douzhi3105 2015-07-22 10:46
    关注

    I've found the solution, there was a bug on the expiration date where I was doing:

    $expiration = (new DateTime())->modify('+3h')->getTimestamp();
    

    So I've changed h to hours so that it works now, like:

    $expiration = (new DateTime())->modify('+3hours')->getTimestamp();
    

    But that didn't quite solved it, the actual missing part is that the Google_Signer_P12::sign() requires it to be encoded on base64, which is specified on the google docs:

    Google Cloud Storage expects the Base64 encoded signature in its APIs.

    However I (wrongly) though that Google_Signer_P12::sign() already would do that, so after I understood that it was required I've changed the sign method to:

    function googleSignString($certificatePath, $stringToSign)
    {
      return base64_encode((new Google_Signer_P12(
        file_get_contents($certificatePath),
        'notasecret'
      ))->sign($stringToSign));
    }
    

    And it is working now!!!

    I've also updated the gist for anyone that wants to use it :)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥40 图书信息管理系统程序编写
  • ¥15 7-1 jmu-java-m02-使用二维数组存储多元线性方程组
  • ¥20 Qcustomplot缩小曲线形状问题
  • ¥15 企业资源规划ERP沙盘模拟
  • ¥15 树莓派控制机械臂传输命令报错,显示摄像头不存在
  • ¥15 前端echarts坐标轴问题
  • ¥15 ad5933的I2C
  • ¥15 请问RTX4060的笔记本电脑可以训练yolov5模型吗?
  • ¥15 数学建模求思路及代码
  • ¥50 silvaco GaN HEMT有栅极场板的击穿电压仿真问题