【问题标题】:Signed URL for google bucket does not match signature provided谷歌存储桶的签名 URL 与提供的签名不匹配
【发布时间】:2015-07-21 10:06:22
【问题描述】:

我很难使用谷歌存储。

所以我正在尝试创建一个signed url,已经有了客户端 ID(这是一封电子邮件)和私钥(如 here 所述)所以:

第 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;
}

到目前为止一切顺利(我认为),回显输出看起来与示例相似,所以现在对字符串进行签名

第 2 步:signing the string 最初我使用的是 openssl_public_encrypt,经过搜索发现 google-api-php-client 具有 Google_Signer_P12(实际上使用 openssl_sign),因此该方法如下所示:

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

在这里我不确定这是否正确签名,最终构建最终网址

第 3 步:building the URL

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

但是在浏览器中打开网址会检索到:

<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>

我添加了一个gist 和最终脚本,以便于阅读

所以知道我做错了什么吗?

【问题讨论】:

    标签: php google-cloud-storage google-api-php-client signing


    【解决方案1】:

    我找到了解决方案,我正在做的过期日期有一个错误:

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

    所以我将 h 更改为 hours 以便它现在可以工作,例如:

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

    但这并没有完全解决它,实际缺少的部分是Google_Signer_P12::sign() 要求它以base64 编码,这在google docs 中指定:

    Google Cloud Storage 需要在其 API 中使用 Base64 编码签名。

    但是我(错误地)虽然 Google_Signer_P12::sign() 已经这样做了,所以在我明白这是必需的之后,我将 sign 方法更改为:

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

    它现在正在工作!!!

    我还为任何想要使用它的人更新了gist :)

    【讨论】:

    • 我无法让标头正常工作。每当我尝试添加签名时,我都会收到签名错误。您介意举一个在答案中添加标题的示例吗?
    • 如果您看一下Sign Urls#Construct-the-String,它会解释我的标头 ($headers) 与它们的 Canonicalized_Extension_Headers 匹配的位置。有几个示例。标头是可选的,如果您需要检查它可能必须发送的某些特定标头,这可能是一项要求。
    猜你喜欢
    • 1970-01-01
    • 2021-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多