如何随机生成一个指向文件的链接?

3
我有一个PDF文件,不想在我的网站上公开访问。为了增加一定的安全性,我想通过电子邮件向用户发送一个唯一的、随机生成的URL,用户可以从该URL下载文件,而我将文件存储在AWS或类似的位置。
我感觉自己被困在routes.rb中,不知道如何动态生成URL,也不知道如何正确地创建随机URL,跟踪它们的状态,或者将它们与本地或AWS上存储的文件链接起来。
是否有人对解决这个问题有任何建议?
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。然后,在任何相关的控制器中,您只需要为文件本身编写一个“show”方法,该方法在访问时快速重定向到私有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

4

啊,是的,我以前做过这个。我假设你会使用文件上传宝石,例如Paperclip,并创建了一个名为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'

在Pdfs控制器中添加get_hidden操作:

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,当用户访问该URL时,您的应用程序将通过该令牌在数据库中查找记录,在AWS上获取PDF的实际URL,并从中读取数据并强制浏览器下载所有内容,而无需向最终用户显示真实的URL。请注意,HTML标签已被保留。

2

有很多不同的方法来解决这个问题。可能最简单的方法就是创建一个基于数据库的模型,存储PDF的引用和随机ID。然后show动作将是一个链接格式为/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

在routes.rb文件中。
resources :obscured_pdfs, only: :show

隐蔽类

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

更好的方法是在pdf类中添加“obscured_id”字段,但如果多个人需要不同的链接访问相同的pdf,则此方法效果不佳。我个人最喜欢的选项是对基于“user_id”和“pdf_id”的“随机”id进行对称加密,这样您就不需要存储它了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接