【问题标题】:Streaming Amazon S3 Objects From a Web Server Using Laravel使用 Laravel 从 Web 服务器流式传输 Amazon S3 对象
【发布时间】:2015-10-19 12:54:14
【问题描述】:

在我使用 laravel 5.1 构建的 Web 应用程序中,用户可以上传一些我存储在 Amazon S3 中的敏感文件。稍后我希望用户有许可 下载此文件。由于我希望进行此身份验证检查,因此我无法使用传统方法通过直接链接到 S3 中的文件来下载文件。

我的做法:

  1. 当用户请求下载时,我的服务器会在本地下载文件,然后流式传输给用户。 问题:需要很长时间,因为有时文件太大。

  2. 为用户提供一个预签名 URL,以便直接从 S3 下载。 URL 仅在 5 分钟内有效。 问题:如果该 URL 是共享的,任何人都可以在 5 分钟内下载它。

  3. According to this article,将数据直接从 S3 流式传输到客户端。这看起来很有希望,但我不知道如何实现。

根据这篇文章,我需要:

  1. 注册流包装器 - 这是我的第一个问题,因为我不知道如何获取 S3Client 对象,因为 laravel 使用 flysystem,而且我不知道要调用什么方法来获取它目的。也许我需要在我的 composer.json 中单独包含 S3 包?
  2. 禁用输出缓冲 - 我需要在 laravel 中执行此操作还是 laravel 已经处理了它?

我相信其他开发人员之前已经看到过这样的问题,并希望获得一些帮助。如果有人已经使用 laravel Response::download($pathToFile, $name, $headers) 直接从 S3 流式传输到客户端,那么我很想听听你的方法。

【问题讨论】:

  • 不是来自 S3->user 的流,是流 S3->Laravel->user。您的服务器仍在循环中,因此您会产生带宽并错过直接从 S3 提供服务的大部分好处。
  • @ceejayoz 我明白,但我有什么选择。我无法直接访问 S3 中的文件。另外,我必须让文件公开可见,以便其他人下载。
  • 您可能可以用temporary IAM credentials 拼凑一些东西,将签名 URL 的使用限制为特定 IP。
  • @ceejayoz 感谢您的链接。但是,如果我的用户被授予 IAM 角色,他们必须是 AWS/Amazon 的一部分还是必须登录?
  • 只要请求开始,就会被允许完成。顺便说一句,如果您将 CloudFront 放在 S3 之前,您的签名 URL 可以限制为 IP 地址。请参阅docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/… - "IpAddress":{"AWS:SourceIp":"optional IP address"} - 这将为您的方案增加一些额外的安全性。

标签: laravel amazon-s3 laravel-5 flysystem


【解决方案1】:

从 cmets 的讨论中,我得出了一些我想分享的关键点。

Pre-Signed URLs

正如@ceejayoz 指出的那样,pre-signed URL 不是一个坏主意,因为:

  1. 我可以将时间保持在 10 秒以内,这对于任何重定向和开始下载来说都是完美的,但对于共享链接来说还不够。
  2. 我之前的理解是下载必须在给定时间内完成。因此,如果链接在 10 秒后过期,则必须在此之前进行下载。但@ceejayoz 指出事实并非如此。允许完成已开始的下载。
  3. 使用cloud front,我还可以限制IP 地址,以增加安全性。


IAM Roles

他还指出了另一个不太好的方法 - 创建临时 IAM 用户。如果没有正确完成,这将是一场维护噩梦,所以只有在您知道自己在做什么的情况下才可以这样做。


Stream From S3

这是我目前选择的方法。也许稍后我会转向第一种方法。

警告:如果您进行流式传输,那么您的服务器仍然是中间人,所有数据都将通过您的服务器传输。因此,如果它失败或速度很慢,您的下载速度就会很慢。

我的第一个问题是 how to register stream wrapper:

由于我使用 Laravel 并且 laravel 使用 flysystem 进行 S3 管理,所以我没有简单的方法来获取 S3Client。因此我在我的composer.json 中添加了额外的包AWS SDK for Laravel

"aws/aws-sdk-php-laravel" : "~3.0"

然后我写了我的代码如下:

class FileDelivery extends Command implements SelfHandling
{
    private $client;
    private $remoteFile;
    private $bucket;

    public function __construct($remoteFile)
    {
        $this->client = AWS::createClient('s3');
        $this->client->registerStreamWrapper();
        $this->bucket = 'mybucket';
        $this->remoteFile = $remoteFile;
    }

    public function handle()
    {
        try
        {
            // First get the meta-data of the object.
            $headers = $this->client->headObject(array(
                'Bucket' => $this->bucket,
                'Key' => $this->remoteFile
            ));

            $headers = $headers['@metadata'];
            if($headers['statusCode'] !== 200)
            {
                throw new S3Exception();
            }
        }
        catch(S3Exception $e)
        {
            return 404;
        }

        // return appropriate headers before the stream starts.
        http_response_code($headers['statusCode']);
        header("Last-Modified: {$headers['headers']['last-modified']}");
        header("ETag: {$headers['headers']['etag']}");
        header("Content-Type: {$headers['headers']['content-type']}");
        header("Content-Length: {$headers['headers']['content-length']}");
        header("Content-Disposition: attachment; filename=\"{$this->filename}\"");

        // Since file sizes can be too large,
        // buffers can suffer because they cannot store huge amounts of data.
        // Thus we disable buffering before stream starts.
        // We also flush anything pending in buffer.
        if(ob_get_level())
        {
            ob_end_flush();
        }
        flush();

        // Start the stream.
        readfile("s3://{$this->bucket}/{$this->remoteFile}");
    }
}

我的第二个问题是 Do I need to Disable output buffering in laravel?

恕我直言,答案是肯定的。缓冲使数据立即从缓冲区中刷新,从而降低内存消耗。由于我们没有使用任何 laravel 函数将数据卸载到客户端,这不是 laravel 做的,因此需要我们做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 2018-02-16
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 2018-06-08
    相关资源
    最近更新 更多