在 Rails 应用中保护 public/的内容 [英] Protecting the content of public/ in a Rails app

查看:59
本文介绍了在 Rails 应用中保护 public/的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm maintaining a Rails app that has content in the public/ folder that will now need to be protected by a login. We're considering moving those folders of files into a path outside of public/ and writing a Rails controller to serve up the content.

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

Before we begin writing this, I was curious if anyone else has ran into this sort of problem? I looked for some gems / plugins that might already do this but didn't find anything. Has anyone created a gem for this?

推荐答案

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

I've done this on a site where people pay to download certain files, and the files are stored in RAILS_ROOT/private. The first thing to know is that you want the web server to handle sending the file, otherwise your app will be held up transmitting large files and this will quickly bring your site to a halt if you have any kind of download volume. So, if you need to check authorization in a controller, then you also need a way to pass control of the download back to the web server. The best way of doing this (that I know of) is the X-Sendfile header, which is supported by Nginx, Apache (with module), and others. With X-Sendfile configured, when your web server receives a X-Sendfile header from your app, it takes over sending the file to the client.

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

Once you have X-Sendfile working for your web server, a private controller method like this is helpful:

##
# 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

那么您的控制器操作可能如下所示:

Then your controller action could look something like this:

##
# 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 内容类型).

Obviously your authorization method will vary and you'll need to change the headers if you're offering files other than PDFs or you want the file to be viewed in the browser (get rid of application/force-download content type).

这篇关于在 Rails 应用中保护 public/的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆