google-app-engine - 为什么 Google Storage API 不能与 Amazon SDK v3 一起使用?

标签 google-app-engine google-api laravel-5 google-cloud-storage google-api-php-client

我觉得在这里发布这个很奇怪,但由于 SO 是 Google API 支持的唯一官方 channel ,我想我需要在这里提问。

If you have API, tool usage, or other software development-related questions, search for and post questions on Stack Overflow, using the official google-cloud-storage tag.

好的,就这样吧。我花了两天的大部分时间努力让 Google Storage 在 Amazon 的 PHP SDK 的 v3 版本(最新)上运行。我不能使用旧版本的 SDK,因为我试图坚持使用 Laravel 5.1 的文件系统,而不必为 Google Storage 编写全新的驱动程序。我相信这符合 Google 宣传 Google Storage 的精神:

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

In a simple migration from Amazon S3 to Google Cloud Storage, you can use your existing tools and libraries for generating authenticated REST requests to Amazon S3, to also send authenticated requests to Google Cloud Storage. The changes you need to make to your existing tools and libraries are described in this section.

To get set up for a simple migration do the following:

Set a default Google project.

Get a developer key.

In your existing tools or libraries, make the following changes: Change the request endpoint to use the Google Cloud Storage request endpoint. Replace the Amazon Web Services (AWS) access and secret key with the corresponding Google Cloud Storage access key and secret key (collectively called your Google developer key).

That's it! At this point you can start using your existing tools and libraries to send keyed-hash message authentication code (HMAC) requests to Google Cloud Storage.

多好的一个音调!让我们尝试使用可使用 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";
}

不起作用。你得到一个“不正确的身份验证 header ”。让我们看一下该 header 。

AWS4-HMAC-SHA256 Credential=GOOGGUxxxxxxxxxxx/20150611/US/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=9c7de4xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

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

Google Storage Incorrect Authorization Header with Amazon S3 PHP SDK v3

让我们试试看:

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

运气不好。同样的错误。授权 header 没有改变。让我们看一下 S3Client 的代码,看看“签名”是如何使用的:

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

事实并非如此。所以现在我们偏离了 S3 的官方文档,因为他们说了同样的话:

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

这不是“签名”,而是“签名版本”。让我们将其更改为 v2。

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

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

UnresolvedSignatureException in SignatureProvider.php line 61: Unable to resolve a signature for v2/s3/US. Valid signature versions include v4 and anonymous.

所以,在玩弄了两天之后,这似乎是不可能的,至少不是 Google 希望您相信他们的推销那样轻松。我根本无法让它工作,所以我希望这里有人可以对此有所了解。要么我错过了一些重要的东西,要么谷歌错误地宣传谷歌存储使用亚马逊的 S3 SDK 工作并浪费开发人员的时间。我在想也许我们必须手动劫持授权 header ,但这超出了我的专业知识范围。任何帮助将不胜感激。

最佳答案

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

您必须提供自己的提供商,但设置起来并不难。只需在 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']));
        });
    }
}

基本上在您的配置中,您只是在 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'),
],

最后但同样重要的是,您还需要将提供者添加到 app.php 中的提供者列表中

'providers' => [
    ...
    App\Providers\GcsAppsServiceProvider::class,
],

AWS S3 适配器还提到 GCS supports it in their documentation .

关于google-app-engine - 为什么 Google Storage API 不能与 Amazon SDK v3 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30790265/

相关文章:

ios - Google Places API 警告

node.js - 如何获取Google Ads API以获取帐户列表

python - 在 App Engine 的特定日期每小时安排一个 cron 作业执行

google-app-engine - 用于 Google App Engine 的 Java MVC

google-api - Google API 给出未经授权的 token 错误

php - 如何在自定义类 laravel 5 中使用 session ?

mysql - Eloquent 查询不能正常工作

html - 使用多部分/表单数据时如何从请求中获取字符串参数?

python - 每当我重新启动系统并启动 GAE Launcher 时,Google App Engine 都会出错

php - 试图让电子邮件在 Laravel 5 中工作