Рейтинг:1

Можно ли разрешить анонимным пользователям просматривать временный управляемый файл через hook_file_download()?

флаг ng

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

У меня есть система на основе токенов для защиты файла, но проблема, похоже, в том, что файл является временным. Я создал hook_file_download(), чтобы возвращать заголовки по мере необходимости, чтобы разрешить доступ после утверждения, но доступ к файлу все еще где-то запрещен.

Похоже, это не проблема веса модуля, поскольку я сделал свой пользовательский модуль с наименьшим весом и проверил с помощью кода отладки, что он срабатывает после ядра file_file_download().

РЕДАКТИРОВАТЬ: дальнейшее устранение неполадок показывает, что массив заголовков получает значение ключа, установленное на «-1», где-то после hook_file_download() и ядра «FileDownloadController», где файл получает отказ. Есть идеи, где устанавливается это значение заголовка [0] = -1 и как его переопределить?

Если я уменьшу его до основ для тестирования, как показано ниже, заголовки «разрешить» будут возвращены, но файл по-прежнему будет заблокирован при просмотре из анонимного браузера:

функция MYMODULE_file_download($uri) {

  // Проверяем, не является ли это загрузкой конфигурации.
  $схема = StreamWrapperManager::getScheme($uri);

  если ($ схема == 'временно'){
    if ($files = \Drupal::entityTypeManager()->getStorage('file')->loadByProperties(['uri' => $uri])){

      $file = reset($files) ?: NULL;
      
      // Доступ разрешен.
      $headers = file_get_content_headers($file);
      вернуть $заголовки;
    }
  }
}
Рейтинг:1
флаг us

Временные файлы обрабатываются file_file_download(), реализация hook_file_download() делается из модуля File. Код, который он использует, следующий.

  // Узнаем, используется ли в системе еще временный файл.
  если ($file->isTemporary()) {
    $usage = \Drupal::service('file.usage')->listUsage($file);
    если (пусто($usage) && $file->getOwnerId() != \Drupal::currentUser()
      ->id()) {
      // Запретить доступ к временным файлам без использования, которые не принадлежат
      // тот же пользователь. Это предотвращает проблему безопасности, связанную с тем, что личный файл,
      // было защищено правами доступа к полю, становится доступным после его использования
      // был удален и до того, как он действительно был удален из файловой системы.
      // Модули, зависящие от этого поведения, должны сделать файл постоянным
      // вместо.
      возврат -1;
    }
  }

Чтение комментариев, сделанное специально, чтобы избежать приватного файла, защищенного разрешениями поля, видно после изменения разрешений поля, но до удаления файла.

Глядя на код, который вызывает этот хук, в FileDownloadController::download() например, я не вижу способа избежать этого, так как код не использует hook_file_download_alter().

Обходным путем может быть установка этого файла как используемого, поскольку код проверяет, что файл не используется, прежде чем блокировать доступ.

функция mymodule_file_download($uri) {
  если (StreamWrapperManager::getScheme($uri) == 'временный') {
    if ($files = \Drupal::entityTypeManager()->getStorage('file')->loadByProperties(['uri' => $uri])){
      если ($ файл = сбросить ($ файлы)) {
        // Доступ разрешен.
        \Drupal::service('file.usage')->добавить($file, 'mymodule', 'unexisting_entity', 10);
        $headers = file_get_content_headers($file);
        вернуть $заголовки;
      }
    }
  }
}

я использовал 'несуществующий_сущность' и 10 как тип объекта и идентификатор объекта. Если у вас есть реальные значения для них, вы должны использовать их.

Обратите внимание, что FileUsageBase:: добавить(), DatabaseFileUsageBackend::add() родительский метод изменяет файл на постоянный, если это еще не так.

// Убедитесь, что используемый файл является постоянным.
если (!$file->isPermanent()) {
  $файл->setPermanent();
  $файл->сохранить();
} 

Когда использование файла уменьшается и становится равным 0, файл становится временным с FileUsageBase::удалить().

// Если больше не осталось использований этого файла, пометить его как временное,
// что приводит к удалению через system_cron().
$usage = \Drupal::service('file.usage')->listUsage($file);
если (пусто($использование)) {
  $файл->setTemporary();
  $файл->сохранить();
}

Я бы предпочел увеличить использование файла вместо того, чтобы сделать файл постоянным, поскольку уменьшение использования файла не конфликтует с другими модулями, которые могут установить тот же файл в качестве постоянного.
В качестве альтернативы я бы использовал следующий код для hook_file_download().

функция mymodule_file_download($uri) {
  если (StreamWrapperManager::getScheme($uri) == 'временный') {
    if ($files = \Drupal::entityTypeManager()->getStorage('file')->loadByProperties(['uri' => $uri])){
      если ($ файл = сбросить ($ файлы)) {
        // Доступ разрешен.
        если (!$file->isPermanent()) {
          $файл->setPermanent();
          $файл->сохранить();
        }
        $headers = file_get_content_headers($file);
        вернуть $заголовки;
      }
    }
  }
}

В этом случае, чтобы снова сделать файл временным, я бы использовал следующий код.

// Сохраняем ссылку на объект файла в $file.
$usage = \Drupal::service('file.usage')->listUsage($file);
если (пусто($usage) && !$file->isTemporary()) {
  $файл->setTemporary();
  $файл->сохранить();
}

Чтобы добиться желаемого, можно было бы также изменить контроллер для система.временный маршрут, но это кажется чрезмерным.

quantumized avatar
флаг ng
Спасибо, да, этот фрагмент file_file_download() является виновником. Я не понимаю, почему я не могу использовать hook_file_download() в моем модуле с более высоким весом, чтобы переопределить это.
quantumized avatar
флаг ng
Я нашел обходной путь, установив для файла значение «isPermanent», но мне это не нравится. Знаете ли вы, не приведет ли это к тому, что файлы не будут удалены из системы при необходимости?
apaderno avatar
флаг us
`hook_file_download()` получает только URL, а не заголовки, возвращаемые другими реализациями; если бы это было так, реализация ловушки могла бы переопределить решение другой реализации. Фактический код, вызывающий их, просто проверяет, что один из них возвращает -1 в качестве заголовка; он не проверяет -1 - это первое возвращаемое значение.
apaderno avatar
флаг us
@quantumized Постоянные файлы не будут удалены в процессе сборки файлового мусора, но модуль может их удалить. Если модуль хранит список файлов, которые он изменил на постоянный, это возможно.
apaderno avatar
флаг us
Я также добавил примечание о том, что происходит, когда увеличивается использование файла: Реализация ядра Drupal службы *file.usage* автоматически делает временный файл постоянным.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.