19

我正在维护一个 Rails 应用程序,该应用程序在 public/ 文件夹中包含现在需要通过登录来保护的内容。我们正在考虑将这些文件文件夹移动到 public/ 之外的路径中,并编写一个 Rails 控制器来提供内容。

在我们开始写这篇文章之前,我很好奇是否有其他人遇到过这种问题?我寻找了一些可能已经这样做但没有找到任何东西的宝石/插件。有没有人为此创造了一个宝石?

4

5 回答 5

17

我在一个人们付费下载某些文件的网站上完成了这项工作,这些文件存储在RAILS_ROOT/private. 首先要知道的是,您希望 Web 服务器处理发送文件,否则您的应用程序将被阻止传输大文件,如果您有任何类型的下载量,这将很快使您的网站停止运行。因此,如果您需要在控制器中检查授权,那么您还需要一种将下载控制权传递回 Web 服务器的方法。执行此操作的最佳方法(据我所知)是 X-Sendfile 标头,Nginx、Apache(带模块)等都支持该标头。配置 X-Sendfile 后,当您的 Web 服务器X-Sendfile从您的应用程序接收到标头时,它会接管将文件发送到客户端。

一旦 X-Sendfile 为您的 Web 服务器工作,像这样的私有控制器方法会很有帮助:

##
# Send a protected file using the web server (via the x-sendfile header).
# Takes the absolute file system path to the file and, optionally, a MIME type.
#
def send_file(filepath, options = {})
  options[:content_type] ||= "application/force-download"
  response.headers['Content-Type'] = options[:content_type]
  response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filepath)}\""
  response.headers['X-Sendfile'] = filepath
  response.headers['Content-length'] = File.size(filepath)
  render :nothing => true
end

然后您的控制器操作可能如下所示:

##
# Private file download: check permission first.
#
def download
  product = Product.find_by_filename!(params[:filename])
  if current_user.has_bought?(product) or current_user.is_superuser?
    if File.exist?(path = product.filepath)
      send_file path, :content_type => "application/pdf"
    else
      not_found
    end
  else
    not_authorized
  end
end

显然,您的授权方法会有所不同,如果您提供 PDF 以外的文件,或者您希望在浏览器中查看文件(摆脱application/force-download内容类型),则需要更改标题。

于 2010-01-26T23:12:09.790 回答
2

您可以使用 Amazon S3。您可以使用控制器在您的安全区域后面生成和提供 url,它还有一个功能,即一旦生成 url,资源基本上只在一定时间内可用。

查看此网址:http ://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTAuthentication.html

于 2010-01-26T23:03:11.567 回答
1

AFAIK,nginx 不支持 X-SendFile。Nginx 有自己的扩展,称为 X-Accel-Redirect。

您将在此处找到有关此内容的更多信息: https ://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/

在 github 上还有一个 rails 插件实现了这个功能:goncalossilva/X-Accel-Redirect

于 2010-07-06T10:15:48.443 回答
0

使文件在不可预知的 URL上可用是目前在某些生产系统中使用的简单解决方案。

例如:GitLab。下图上传到了一个私有仓库的 issue,https://gitlab.com/cirosantilli/test-private/issues/1,但是你仍然可以看到它:

请注意90574279de自动添加到 URL 的不可猜测的前缀。

Bitbucket(非 Rails)也使用这种技术。

于 2014-11-22T08:53:56.437 回答
0

如果您想将内容交付与您的 Rails 身份验证和授权系统联系起来,那么您基本上必须将内容放在控制器后面。

如果您正在寻找一种更简单的登录方法,您可以使用 HTTP Auth 和托管环境中的设置来处理它(例如,使用 htaccess)。

于 2010-01-26T23:07:26.867 回答