我正在维护一个Rails应用程序,其内容在公共/文件夹中,现在需要受到登录的保护.我们正在考虑将这些文件夹移动到公共场所之外的路径中,并编写一个Rails控制器来提供内容.
在我们开始撰写之前,如果有人遇到这样的问题,我很好奇?我寻找一些可能已经这样做但没有找到任何东西的宝石/插件.有没有人为此创造了宝石?
解决方法
我在一个人们付费下载某些文件的网站上完成了这些操作,文件存储在RAILS_ROOT / private中.首先要知道的是,您希望Web服务器处理发送文件,否则您的应用程序将被阻止传输大文件,如果您有任何下载量,这将很快使您的站点停止.因此,如果您需要在控制器中检查授权,那么您还需要一种方式将下载的控制权传回到Web服务器.这样做的最好的方法(我知道的)是Nginx,Apache(与模块)等支持的X-Sendfile头文件.配置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以外的其他文件,或者您希望在浏览器中查看文件(摆脱应用程序/强制下载内容类型),则需要更改标题.