我有一个 PDF 文件,我不想从我网站上的 URL 公开访问。作为一个(轻微的)安全层,我想通过电子邮件向用户发送一个随机生成的唯一 URL,他们可以从中下载 PDF,我将把它存储在 AWS 或类似的东西上。
我觉得我被困在了 routes.rb 监狱中,我不知道如何动态生成 URL,也不知道如何正确创建随机 URL、跟踪它们,或者将它们链接到本地或 AWS 上存储的文件。
有人对解决这个问题有什么建议吗?
我有一个 PDF 文件,我不想从我网站上的 URL 公开访问。作为一个(轻微的)安全层,我想通过电子邮件向用户发送一个随机生成的唯一 URL,他们可以从中下载 PDF,我将把它存储在 AWS 或类似的东西上。
我觉得我被困在了 routes.rb 监狱中,我不知道如何动态生成 URL,也不知道如何正确创建随机 URL、跟踪它们,或者将它们链接到本地或 AWS 上存储的文件。
有人对解决这个问题有什么建议吗?
您如何存储 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
啊,是的,我以前做过。我假设您将使用诸如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。
有很多不同的方法可以解决这个问题。可能最简单的方法就是创建一个数据库支持的模型,该模型存储对 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_id
and对称地加密“随机”id,pdf_id
这样您根本不需要存储它。