29

我有一个托管在 Heroku 上的 Rails 应用程序。该应用程序在 Amazon S3 上生成和存储 PDF 文件。用户可以下载这些文件以在浏览器中查看或保存在计算机上。

我遇到的问题是,虽然可以通过 S3 URL(如“https://s3.amazonaws.com/my-bucket/F4D8CESSDF.pdf”)下载这些文件,但这显然不是一个好方法它。向用户公开这么多有关后端的信息是不可取的,更不用说随之而来的安全问题了。

是否可以让我的应用程序以某种方式从控制器中的 S3 检索文件数据,然后为用户创建下载流,以便不暴露亚马逊 URL?

4

3 回答 3

58

您可以将 s3 对象创建为私有对象,并使用url_for方法 (aws-s3 gem) 为它们生成临时公共 url。这样,您就不会通过更具可扩展性的应用服务器流式传输文件。它还允许放置基于会话的授权(例如在您的应用中设计)、跟踪下载事件等。

为此,请将指向 s3 托管文件的直接链接更改为指向控制器/操作的链接,从而创建临时 url 并重定向到它。像这样:

class HostedFilesController < ApplicationController

  def show
    s3_name = params[:id] # sanitize name here, restrict access to only some paths, etc
    AWS::S3::Base.establish_connection!( ... )
    url = AWS::S3::S3Object.url_for(s3_name, YOUR_BUCKET, :expires_in => 2.minutes)
    redirect_to url
  end

end

在下载 url 中隐藏亚马逊域通常是通过 DNS 别名来完成的。您需要创建别名为您的子域的 CNAME 记录downloads.mydomain,例如s3.amazonaws.com. 然后您可以在其中指定:server选项AWS::S3::Base.establish_connection!(:server => "downloads.mydomain", ...),S3 gem 将使用它来生成链接。

于 2012-09-05T13:34:23.663 回答
11

是的,这是可能的——只需使用 Rails 获取远程文件并将其临时存储在您的服务器上或直接从缓冲区发送。这样做的问题当然是您需要先获取文件,然后才能将其提供给用户。请参阅此线程进行讨论,他们的解决方案是这样的:

#environment.rb
require 'open-uri'

#controller
def index
  data = open(params[:file])
  send_data data, :filename => params[:name], ...
end

这个问题也有些相关

于 2012-09-05T12:39:05.780 回答
-1

首先,您需要在您的域中创建一个 CNAME,如在此处解释。

其次,您需要创建一个与您放入 CNAME 的名称相同的存储桶。

最后,您需要在 config/initializers/carrierwave.rb 中添加此配置:

CarrierWave.configure do |config|
    ...  
    config.asset_host         = 'http://bucket_name.your_domain.com'
    config.fog_directory      = 'bucket_name.your_domain.com'
    ...
end
于 2014-04-01T17:54:38.193 回答