3

我有一个 PDF 文件,我不想从我网站上的 URL 公开访问。作为一个(轻微的)安全层,我想通过电子邮件向用户发送一个随机生成的唯一 URL,他们可以从中下载 PDF,我将把它存储在 AWS 或类似的东西上。

我觉得我被困在了 routes.rb 监狱中,我不知道如何动态生成 URL,也不知道如何正确创建随机 URL、跟踪它们,或者将它们链接到本地​​或 AWS 上存储的文件。

有人对解决这个问题有什么建议吗?

4

3 回答 3

5

您如何存储 PDF?如果您使用的是Paperclip 之类的东西,您可以很容易地为私有文件生成一个临时公共 URL:

class Attachment < ActiveRecord::Base

  has_attached_file :file

  # ...

  def file_url
    file.expiring_url(10)
  end

end

file_url将为该文件生成一个 10 秒有效的 URL。然后,在任何相关的控制器中,您都可以为文件本身提供一个“显示”方法,该方法在访问时快速重定向到私有 url:

class AttachmentsController < ApplicationController

  # GET /whatever/attachments/:id
  def show
    redirect_to Attachment.find(params[:id]).file_url
  end

end

要获得您将要发送的“随机”URL,您需要一个额外的步骤。您可以使用类似的东西生成一个长哈希SecureRandom.uuid,并将其作为参数传递,使用类似的简单模型AttachmentProxy

就像是:

class AttachmentProxy < ActiveRecord::Base

  has_one :attachment

  # has an attribute called 'key', indexed...

end

在你的控制器中:

class AttachmentProxyController < ApplicationController

  def show
    proxy = AttachmentProxy.find_by_key(params[:key])
    redirect_to proxy.attachment.file_url
  end

end
于 2013-11-07T22:06:27.583 回答
4

啊,是的,我以前做过。我假设您将使用诸如Paperclip之类的文件上传 gem,并创建了一些模型,例如 Pdf,例如:

class Pdf < ActiveRecord::Base
  has_attached_file :pdf, storage: :s3
end

这将设置模型,以便您可以将文件上传到它,并将其存储在 AWS S3 中。您目前可能没有这种方式,但我们的想法是拥有一个数据库记录,您可以在其中引用 Pdf 的 URL,以及用户将用于在不知道真实 URL 的情况下检索它的唯一令牌。

在 Pdf 模型中,您应该有一个 token:string 字段,并且在模型的 before_save 过滤器中生成唯一令牌:

class Pdf < ActiveRecord::Base
  require 'securerandom'
  has_attached_file :pdf, storage: :s3
  before_save :generate_unique_token

  private

  def generate_unique_token
    self.token ||= SecureRandom.hex
  end
end

现在你可以设置一个命名路由:

get '/hidden_pdf/:token', to: 'pdfs#get_hidden'

将 get_hidden 操作添加到 Pdfs 控制器:

class PdfsController < ApplicationController
  def get_hidden
    pdf = Pdf.where(token: params[:token]).first

    if pdf
      # from the pdf model you have access to its real URL and you can send it directly
      data = open pdf.url
      send_data data.read, filename: pdf.pdf_file_name, type: "application/pdf", disposition: 'inline', stream: 'true', buffer_size: '4096'
    else
      # Not found logic here
    end
  end
end

现在您只需向您的用户发送一个 URL,例如myapp.com/pdfs/random-string-here,当他们访问它时,您的应用程序将通过该令牌在数据库中找到记录,在 AWS 上提取 PDF 的真实 URL ,从中读取数据并强制下载到浏览器,而无需向最终用户显示真实的 URL。

于 2013-11-07T22:05:13.867 回答
2

有很多不同的方法可以解决这个问题。可能最简单的方法就是创建一个数据库支持的模型,该模型存储对 pdf 和随机 id 的引用。然后显示操作将是格式的链接/obscured_pdf/asdkfjlkdafj1230-5324.pdf或您想出的任何随机 id。因此,对于一个基本示例:

控制器

class ObscuredPdfsController < ApplicationController
  def show
    @pdf = ObscuredPdf.find_by_obscured_id(params[:id]).pdf
    # render pdf, do whatever
  end
end

在路线.rb

resources :obscured_pdfs, only: :show

遮蔽类

class ObscuredPdf < ActiveRecord::Base
  belongs_to :pdf
  belongs_to :user
  attr_accessible :obscured_id
end

更好的是,将该obscured_id字段添加到 pdf 类中,尽管如果多人需要指向同一个 pdf 的不同链接,这也不起作用。就我个人而言,我最喜欢的选择是基于user_idand对称地加密“随机”id,pdf_id这样您根本不需要存储它。

于 2013-11-07T22:04:20.210 回答