Защита контента public / в приложении Rails - PullRequest
17 голосов
/ 27 января 2010

Я поддерживаю приложение Rails, содержимое которого находится в общедоступной папке / папке, которая теперь должна быть защищена входом в систему.Мы рассматриваем перемещение этих папок с файлами в путь за пределами public / и написание контроллера Rails для обслуживания контента.

Прежде чем мы начнем писать это, мне было бы любопытно, сталкивался ли кто-либо еще с подобным видомпроблемы?Я искал некоторые драгоценные камни / плагины, которые могли бы уже сделать это, но ничего не нашли.Кто-нибудь создал для этого драгоценный камень?

Ответы [ 5 ]

16 голосов
/ 27 января 2010

Я сделал это на сайте, где люди платят за скачивание определенных файлов, а файлы хранятся в RAILS_ROOT/private. Первое, что нужно знать, это то, что вы хотите, чтобы веб-сервер обрабатывал отправку файла, иначе ваше приложение будет задерживать передачу больших файлов, и это быстро остановит ваш сайт, если у вас есть какой-либо объем загрузки. Итак, если вам нужно проверить авторизацию в контроллере, то вам также нужен способ передать управление загрузкой обратно на веб-сервер. Лучший способ сделать это (насколько я знаю) - это заголовок X-Sendfile, который поддерживается Nginx, Apache (с модулем) и другими. С настроенным X-Sendfile, когда ваш веб-сервер получает заголовок X-Sendfile от вашего приложения, он берет на себя отправку файла клиенту.

Если у вас есть X-Sendfile, работающий на вашем веб-сервере, вам пригодится такой метод частного контроллера:

##
# 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 типа контента).

2 голосов
/ 27 января 2010

Вы можете использовать Amazon S3. Вы можете использовать контроллеры для генерации и обслуживания URL-адресов за вашей защищенной областью, а также имеет функцию, которая в основном делает ресурсы доступными только на определенное время после создания URL-адреса.

Проверьте этот URL: http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTAuthentication.html

1 голос
/ 06 июля 2010

AFAIK, X-SendFile не поддерживается nginx. У Nginx есть собственное расширение, которое называется X-Accel-Redirect.

Более подробную информацию вы найдете здесь: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/

Существует также плагин rails для реализации этой функции на github: goncalossilva / X-Accel-Redirect

0 голосов

Предоставление доступа к файлу по непредсказуемому URL-адресу - это простое решение, используемое в настоящее время в некоторых производственных системах.

Например: GitLab. Следующее изображение было загружено в номер закрытого репозитория, https://gitlab.com/cirosantilli/test-private/issues/1,, но его все еще можно увидеть:

Обратите внимание на неосуществимый префикс 90574279de, автоматически добавляемый к URL.

Bitbucket (не Rails) также использует эту технику.

0 голосов
/ 27 января 2010

Если вы хотите связать доставку контента с вашей системой аутентификации и авторизации Rails, то вам, по сути, нужно поместить контент за контроллер.

Если вы ищете более простой подход к входу в систему, вы можете справиться с ним с помощью аутентификации HTTP и настроек в вашей среде хостинга (например, с помощью htaccess).

...