如何对与云端一起使用的 s3 对象 URL?

Posted

技术标签:

【中文标题】如何对与云端一起使用的 s3 对象 URL?【英文标题】:How to s3 object URL that works with cloudfront? 【发布时间】:2014-07-18 11:02:47 【问题描述】:

我目前在 S3 上私下存储文件。在我的 Rails 应用程序中,在 attachment.rb 模型中,我可以获得私有文件的公共 URL,如下所示:

def cdn_url ( style='original' )
  attachment.s3_object(style).url_for( :read, secure: true, response_content_type: self.meta['file_content_type'], expires: 1.hour ).to_s
end

问题是这是向 S3 提供 URL 并重写 URL 以使用我的 Cloudfront 源 URL 时出错:

我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。

如何获取如下所示的公共 URL 资产,但通过 Cloudfront 提供资产?

【问题讨论】:

你能分享一个通过cdn_url方法生成的url的例子吗? 【参考方案1】:

第一种方式(简单)

只需使用aws_cf_signer gem。把它放在你的捆绑器中。

有了这个,你可以做类似的事情

def cdn_url (options = )
  style = options[:style] || 'original'
  cloudfront_domain =  options[:cloudfront_domain] || 'example.cloudfront.net'
  cloudfront_pem_key_path = options[:cloudfront_pem_key_path]
  cloudfront_key_paid_id = options[:cloundfrount_key_paid_id] 
  path = attachment.path(style)  #path of the file
  # you can get this values from your aws a/c , most probably by going int 
  # https://console.aws.amazon.com/iam/home?#security_credential      
  signer = AwsCfSigner.new(cloudfront_pem_key_path, cloudfront_key_paid_id)
  # this configuration may vary. 
  # visit https://github.com/dylanvaughn/aws_cf_signer 
  # and check all available settings/options   
  url = signer.sign(path, :ending => Time.now + 3600)
  cloudfront_domain + url
end 

有了这个,你可以用类似这样的方式访问 url

  cdn_url(cloudfront_pem_key_path: '/users/downloads/pri.pem' , cloudfront_key_paid_id: '33243424XXX')

第二种方式

# A simple function to return a signed, expiring url for Amazon Cloudfront. 
# This will require openssl, digest/sha1, base64 and maybe other libraries. 
 
module CloudFront
  def get_signed_expiring_url(domain,path, expires_in, private_key_filename, key_pair_id)
 
    # AWS works on UTC, so make sure you are not using local time
    expires = (Time.now.getutc + expires_in).to_i.to_s
 
    private_key = OpenSSL::PKey::RSA.new(File.read(private_key_filename))
 
    # path should be your S3 path without a leading slash and without a file extension.
    # e.g. files/private/52
    policy = %Q["Statement":["Resource":"#path","Condition":"DateLessThan":"AWS:EpochTime":#expires]]
    signature = Base64.strict_encode64(private_key.sign(OpenSSL::Digest::SHA1.new, policy))
 
    # I'm not sure exactly why this is required, but it's in Amazon's perl script and seems necessary
    # Different base64 implementations maybe? 
    signature.tr!("+=/", "-_~")
    
    "#domain#path?Expires=#expires&Signature=#signature&Key-Pair-Id=#key_pair_id"
  end
end
 

有了这个,你可以做类似的事情

def cdn_url ( style='original',cloudfront_pem_key_path,key_pair_id)
  path = attachment.path(style)  #path of the file
  # you can get this values from your aws a/c , most probably by going int 
  CloudFront.get_signed_expiring_url 'example.cloudfront.net', path, 45.seconds ,'/users/downloads/pri.pem', 'as12XXXXX')
end
 

试一试,也许会奏效。请务必正确设置正确的存储桶访问策略。如果您看到accessDenied 错误http://www.jppinto.com/2011/12/access-denied-to-file-amazon-s3-bucket/,请检查一下

【讨论】:

这真的很棒。面临的挑战是,我有一个现有的 S3 存储桶,目前正在生产中使用。要获得 PEM 密钥,我需要更新 s3 存储桶,使其只能由 Cloudfront 访问,而不是 S3 直接访问,这会破坏一切。有没有办法让 Cloudfront 和 S3 都工作,这样我就不会破坏现有的内容?谢谢 Cloudfront 不关心 s3 文件是否可以直接访问。您只需要允许 cloudfront 允许访问 s3,仅此而已。只需访问此链接console.aws.amazon.com/iam/home?#security_credential 并获取您的 pem 密钥。和你说的完全不一样 如何允许 cloudfront 访问 S3? 另外,关于如何获得 pem 的任何步骤?有任何教程可以获取仅提供所需访问权限的 pem? 建议不要在生产桶中尝试这个。【参考方案2】:

使用aws sdk gem。

见API Documentation

关于生成presigned URL for an operation on the object的详细信息

提供access-key-id和secret-access-key:-

S3 = AWS::S3.new(
 :access_key_id => 'access_key_id',
 :secret_access_key => 'secret_access_key')

在控制器中输入这些行:--

bucket = S3.buckets['bucket_name']
s3_obj = bucket.objects["Path-to-file"]
return s3_obj.url_for(:read, :expires => 60*60).to_s

此链接将在 1 小时后失效。之后链接将无法访问。

【讨论】:

谢谢,但有什么不同,它没有提供 Cloudfront URL?

以上是关于如何对与云端一起使用的 s3 对象 URL?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 python 检索 AWS S3 对象 URL

Amazon S3 + CloudFront 查询特定版本的存储文件

如何通过使用位置 url 从 Node mongo 中删除 s3 对象?

如何使用预签名的 url 将对象放入 amazon s3?

如何配置亚马逊云端以阻止某些 S3 存储桶文件访问?

使用JavaScript将图像URL中的链接从s3转换为文件对象