为什么Google Storage API不适用于Amazon SDK v3?

Cit*_*zen 5 google-app-engine google-api google-cloud-storage google-api-php-client laravel-5

我觉得这里的帖子很奇怪但是因为SO是Google API支持的唯一官方渠道,我想我需要在这里问一下.

如果您有API,工具使用或其他与软件开发相关的问题,请使用官方google-cloud-storage标记搜索和发布Stack Overflow上的问题.

好的,所以这里.我花了两天时间努力让谷歌存储工作在亚马逊PHP SDK的v3版本(最新版本)上.我无法使用旧版本的SDK,因为我试图坚持使用Laravel 5.1的文件系统,而无需为Google存储编写全新的驱动程序.我相信这符合Google为Google存储广告的精神:

https://cloud.google.com/storage/docs/migrating

在从Amazon S3到Google Cloud Storage的简单迁移中,您可以使用现有工具和库生成经过身份验证的Amazon S3 REST请求,还可以将经过身份验证的请求发送到Google Cloud Storage.本节将介绍您需要对现有工具和库进行的更改.

要设置简单迁移,请执行以下操作:

设置默认的Google项目.

获取开发人员密钥.

在现有工具或库中,进行以下更改:更改请求端点以使用Google云端存储请求端点.使用相应的Google云端存储访问密钥和密钥(统称为Google开发人员密钥)替换Amazon Web Services(AWS)访问和密钥.

而已!此时,您可以开始使用现有工具和库将密钥哈希消息身份验证代码(HMAC)请求发送到Google云端存储.

真是太棒了!让我们尝试使用使用gsutil工作的互操作性凭据.

$client = new S3Client([
    'credentials' => [
        'key' => 'GOOGxxxxxxxxxxxxxxx',
        'secret' => 'ZfcOTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    ],
    'region' => 'US',
    'version' => 'latest',
    'endpoint' => 'https://storage.googleapis.com',
]);

try {
    $result = $client->putObject(array(
        'Bucket' => 'devtest',
        'Key' => 'test',
        'Body' => 'Hello world'
    ));

    echo $result['ObjectURL'];
} catch (\Aws\S3\Exception\S3Exception $e) {
    // The AWS error code (e.g., )
    echo $e->getAwsErrorCode() . "\n";
    // The bucket couldn't be created
    echo $e->getMessage() . "\n";
}
Run Code Online (Sandbox Code Playgroud)

不行.您会收到"不正确的身份验证标头".我们来看看那个标题.

AWS4-HMAC-SHA256凭证= GOOGGUxxxxxxxxxxx/20150611/US/s3/aws4_request,SignedHeaders = host; x-amz-content-sha256; x-amz-date,签名= 9c7de4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

此时我创建了一篇关于此的SO帖子,有人建议我添加'signature'=>'v2'.

使用Amazon S3 PHP SDK v3的Google存储不正确的授权标头

我们试试看:

$client = new S3Client([
    'credentials' => [
        'key' => 'GOOGxxxxxxxxxxxxxxx',
        'secret' => 'ZfcOTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    ],
    'region' => 'US',
    'version' => 'latest',
    'endpoint' => 'https://storage.googleapis.com',
    'signature' => 'v2',
]);
Run Code Online (Sandbox Code Playgroud)

没运气.同样的错误.授权标头未更改.让我们看一下S3Client的代码,看看如何使用'signature':

public function createPresignedRequest(CommandInterface $command, $expires)
{
    /** @var \Aws\Signature\SignatureInterface $signer */
    $signer = call_user_func(
        $this->getSignatureProvider(),
        $this->getConfig('signature_version'),
        $this->getApi()->getSigningName(),
        $this->getRegion()
    );

    return $signer->presign(
        \Aws\serialize($command),
        $this->getCredentials()->wait(),
        $expires
    );
}
Run Code Online (Sandbox Code Playgroud)

它没有.所以现在我们偏离了S3的官方文档,因为他们说的是同样的事情:

http://docs.aws.amazon.com/aws-sdk-php/guide/latest/configuration.html

这不是'签名',而是'signature_version'.我们将其改为v2.

$client = new S3Client([
    'credentials' => [
        'key' => 'GOOGxxxxxxxxxxxxxxx',
        'secret' => 'ZfcOTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    ],
    'region' => 'US',
    'version' => 'latest',
    'endpoint' => 'https://storage.googleapis.com',
    'signature_version' => 'v2',
]);
Run Code Online (Sandbox Code Playgroud)

这次至少我们得到了一个不同的错误!

SignatureProvider.php第61行中的UnresolvedSignatureException:无法解析v2/s3/US的签名.有效的签名版本包括v4和匿名.

所以,经过两天玩弄它看起来似乎是不可能的,至少不是因为谷歌希望你相信他们的音调.我根本无法工作,所以我希望这里有人可以对此有所了解.要么我错过了一些重要的事情,要么Google错误地宣称谷歌存储使用亚马逊的S3 SDK并浪费开发人员的时间.我想也许我们必须手动劫持授权标题,但这超出了我的专业知识.任何帮助将不胜感激.

Sie*_*bah 3

所以我会晚一点发帖,说我使用的是 laravel 5.1,你必须在配置时选择是要使用 AWS 还是 GCS,因为你不能安装两个版本aws php 客户端(这将您对 Flysystem 的选择限制为 v2 或 v3。GCS 暂时需要 v2,而 laravel 中的 s3 实现需要 v3。我花了几个小时尝试让 v3 与 GCS 一起使用,但身份验证标头不同,所以我没有打扰。

您确实必须提供自己的提供商,但设置起来并不困难。只需在app/Providers中创建GcsAppsServiceProvider.php

<?php namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Storage;
use Aws\S3\S3Client;
use League\Flysystem\AwsS3v2\AwsS3Adapter;
use League\Flysystem\Filesystem;

class GcsAppsServiceProvider extends ServiceProvider
{
    public function register()
    {

    }

    public function boot()
    {
        Storage::extend('gcs', function( $app, $config )
        {
            $client = S3Client::factory([
                'key'    => $config['key'],
                'secret' => $config['secret'],
                'base_url' => $config['base_url'],
            ]);

            return new Filesystem(new AwsS3Adapter($client, $config['bucket']));
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

本质上,在您的配置中,您只需复制filesystem.php中的 s3 配置并更改区域 -> base_url。您还可以随意将默认值和云更改为gcs以支持谷歌云存储。

's3' => [
    'driver' => 's3',
    'key'    => env('AWS_KEY', 'your-key'),
    'secret' => env('AWS_SECRET', 'your-secret'),
    'region' => env('AWS_REGION','your-region'),
    'bucket' => env('AWS_BUCKET','your-bucket'),
],

'gcs' => [
    'driver' => 'gcs',
    'key'    => env('GCS_KEY', 'your-key'),
    'secret' => env('GCS_SECRET', 'your-secret'),
    'base_url' => env('GCS_BASE_URL','your-base-url'),
    'bucket' => env('GCS_BUCKET','your-bucket'),
],
Run Code Online (Sandbox Code Playgroud)

最后但并非最不重要的一点是,您还需要将提供程序添加到app.php中的提供程序列表中

'providers' => [
    ...
    App\Providers\GcsAppsServiceProvider::class,
],
Run Code Online (Sandbox Code Playgroud)

AWS S3 适配器还在其文档中提到 GCS 支持它