2012-09-05 109 views
26

私はHerokuでホストされているRailsアプリケーションを持っています。アプリはAmazon S3にPDFファイルを生成して保存します。ユーザーは、これらのファイルをブラウザーで表示したり、コンピューターに保存したりすることができます。Rails:実際のS3 URLを表示せずにS3に保存されたファイルのダウンロードを許可する

私が抱えている問題は、これらのファイルのダウンロードはS3 URL(「https://s3.amazonaws.com/my-bucket/F4D8CESSDF.pdf」など)から可能ですが、明らかにそれを行う良い方法。起きているセキュリティ問題はもちろんのこと、バックエンドに関する多くの情報をユーザーに公開することは望ましくありません。

私のアプリがコントローラのS3から何らかの形でファイルデータを取得してから、そのユーザーのダウンロードストリームを作成して、Amazon URLが公開されないようにすることはできますか?

+0

あなたは明らかにそれをダウンロードすることができ、その後、戻って、ユーザーにそれをストリーミングするが、それは特に高速ではありません。 –

答えて

9

はい、可能です.Railsを使用してリモートファイルをフェッチし、一時的にサーバーに格納するか、バッファから直接送信します。この問題はもちろん、ファイルをユーザーに提供する前にまずファイルを取得する必要があるという事実です。

#environment.rb 
require 'open-uri' 

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

This issue is also somewhat related:議論のためのthis threadを参照してください、彼らのソリューションは、このようなものです。

+0

これは簡単なことでした。ありがとうございました。これは私の実際の実装です: def download file_name = "[file_id"] + ".pdf" data = open( "https://s3.amazonaws.com/#{ENV['S3_BUCKET_NAME']}/ "=>" application/pdf "、:disposition => 'attachment'、 :stream => 'true'、:buffer_size => ' 4096 ' end 私はあなたのソリューションを実装するのが最も簡単なので、この問題の解決策としてソリューションを受け入れました。 – futureshocked

+0

Sergeのものもいいです、Railsアプリをダウンロードから解放するというメリットがありますが、それを動作させるにはもう少し作業が必要です。 – futureshocked

+0

ちょうど他の人が知っている、私はこれで2つの問題が見つかりました:1)それはしばらくすることができますサーバーにダウンロードしてから、ユーザーに、 2)ユーザーのための経験は期待通りではありません。代わりに、何かを読み込んでいるように、ブラウザでダウンロードを取得する代わりに、それは見えます。詳細については、http://stackoverflow.com/a/23161355/293280を参照してください。 –

51

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エイリアシングで行われます。 create CNAME record aliasing your subdomainにする必要があります。 downloads.mydomains3.amazonaws.com。次に:serverオプションをAWS::S3::Base.establish_connection!(:server => "downloads.mydomain", ...)に指定すると、S3 gemがリンクを生成するためにこのオプションを使用します。

+0

Serge、あなたの方法を試しました。 http://s3.amazonaws.com/my-bucket/F4D8CED0.pdf?AWSAccessKeyId=my-actual-key&Expires=1346904098&Signature=Wo7wYH6Ek%2FBot3wd2xYbGt4ybSU%3D:URLは次のようになります。しかしそれは、動作します。 私が理想的に見てみたいことは何もアマゾンの言及はなく、http://mydomain.com/download/file.pdf」のようなものではありません。 が、このことは可能ですか? – futureshocked

+0

あなたはCNAMEとそれにかなり近い得ることができますが、それより 'something.mydomain.com /パス/ file.pdf'のようになります。私はそれを反映して答えを更新しました。 –

+0

非常に素晴らしいソリューション、あなたセルジュを感謝。 – futureshocked

-1

まず、説明文hereのように、ドメインにCNAMEを作成する必要があります。

第2に、CNAMEに入れたのと同じ名前のバケットを作成する必要があります。

そして、あなたを終了するには、あなたのconfig /初期化子/ carrierwave.rbでこの設定を追加する必要があります。

CarrierWave.configure do |config| 
    ... 
    config.asset_host   = 'http://bucket_name.your_domain.com' 
    config.fog_directory  = 'bucket_name.your_domain.com' 
    ... 
end 
関連する問題