Ограничение доступа к публичным ассетам
Pimcore имеет следующее стандартное поведение в отношении доставки ассетов:
Все данные, которые сохраняются в качестве ассетов Pimcore, доступны по их URL (например, https://mydomain.com/my-assetfolder/my-asset.jpg), и, следовательно, являются публичными, без необходимости входа в систему или других ограничений доступа!
В связи с этим конфиденциальные данные не должны храниться в виде ассетов Pimcore без дополнительных мер защиты.
Причина такого поведения связана с производительностью. Доставка ассета напрямую через веб-сервер требует значительно меньше ресурсов, чем запуск процесса PHP для каждого запроса ассета (особенно при доставке миниатюр).
Если требуется более строгое ограничение доступа, Pimcore предоставляет два варианта решения этой задачи:
Вариант 1 - Полное ограничение доступа к определенным ассетам
Все конфиденциальные активы необходимо хранить в одной (или нескольких) папках, например, в /protected (чтобы задать
права доступа в бэкенде Pimcore, это необходимо сделать в любом случае).

Apache
В .htaccess проекта доступ к этой папке необходимо ограничить с помощью дополнительного правила перезаписи. Важно,
чтобы это правило было помещено перед правилом перезаписи для доставки ассетов.
...
RewriteRule ^protected/.* - [F,L]
RewriteRule ^var/.*/protected(.*) - [F,L]
RewriteRule ^cache-buster\-[\d]+/protected(.*) - [F,L]
# АССЕТЫ: проверьте, используется ли метод запроса GET (из-за WebDAV) и существует ли запрошенный файл (ассет) в файловой системе, если оба параметра совпадают, доставьте ассет напрямую
...
Nginx
Добавьте следующие части в вашу конфигурацию Nginx сразу после директивы index.
location ~ ^/protected/.* {
return 403;
}
location ~ ^/var/.*/protected(.*) {
return 403;
}
location ~ ^/cache-buster\-[\d]+/protected(.*) {
return 403;
}
Полный пример конфигурации можно найти на этой странице.
Из-за этого правила все ассеты, находящиеся в /protected (включая все их миниатюры), больше не доставляются через веб-сервер.
Следовательно, также не могут быть использованы прямые ссылки для загрузки или теги img, сгенерированные Pimcore для миниатюр.
Все поставки этих ассетов должны выполняться вручную через пользовательский экшен контроллера.
Вариант 2 - Проверка прав доступа перед доставкой
Этот вариант не ограничивает доставку в целом, а перенаправляет запрос ассета к экшену контроллера, который может проверить права доступа с использованием бизнес-логики и затем доставить ассет или нет.
Опять же, все конфиденциальные ассеты необходимо хранить в одной (или нескольких) папках, например, в /protected.

Apache
В .htaccess проекта запросы к ассетам из этой папки должны быть перенаправлены на index.php. Важно,
чтобы это правило было помещено перед правилом перезаписи для доставки ассетов.
...
RewriteRule ^protected/(.*) %{ENV:BASE}/index.php [L]
RewriteRule ^var/.*/protected(.*) - [F,L]
RewriteRule ^cache-buster\-[\d]+/protected(.*) - [F,L]
# АССЕТЫ: проверьте, используется ли метод запроса GET (из-за WebDAV) и существует ли запрошенный файл (ассет) в файловой системе, если оба параметра совпадают, доставьте ассет напрямую
...
Nginx
Добавьте следующие части в вашу конфигурацию Nginx сразу после директивы index.
rewrite ^(/protected/.*) /index.php$is_args$args last;
location ~ ^/var/.*/protected(.*) {
return 403;
}
rewrite ^(/cache-buster-(?:\d+)/protected(?:.*)) /index.php$is_args$args last;
location ~ ^/cache-buster\-[\d]+/protected(.*) {
return 403;
}
Полный пример конфигурации можно найти на этой странице.
В приложении должен быть определён маршрут (в config/routes.yaml) и экшен контроллера который обрабатывает запрос, например, следующим образом:
# config/routes.yaml
# важно, это должны быть верхние маршруты в файле!
asset_protect:
path: /protected/{path}
defaults: { _controller: App\Controller\MyAssetController::protectedAssetAction }
requirements:
path: '.*'
cache_buster_asset_protect:
path: /cache-buster-{id}/protected/{path}
defaults: { _controller: App\Controller\MyAssetController:protectedAssetAction }
requirements:
id: '\d+'
path: '.*'
<?php
namespace App\Controller;
use Pimcore\Controller\FrontendController;
use Pimcore\Model\Asset;
use Pimcore\Model\Asset\Service;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
class MyAssetController extends FrontendController
{
public function protectedAssetAction(Request $request): Response
{
// ВАЖНО!
// Добавьте свой код здесь, чтобы проверить разрешение!
// the following code is responsible to deliver asset & thumbnail contents
// modify it the way you need it for your use-case
$pathInfo = $request->getPathInfo();
$asset = Asset::getByPath($pathInfo);
if ($asset){
$stream = $asset->getStream();
return new StreamedResponse(function () use ($stream) {
fpassthru($stream);
}, 200, [
'Content-Type' => $asset->getMimeType(),
]);
} else {
return Asset\Service::getStreamedResponseByUri($pathInfo);
}
throw new AccessDeniedHttpException('Access denied.');
}
}
Конечно, этот параметр существенно влияет на загрузку сервера и производительность доставки ассетов (и миниатюр). Поэтому рекомендуется доставлять таким образом не все ассеты, а только конфиденциальные!
Вы можете предложить улучшение документации или задать вопрос в комментариях.
Если вам нужна полноценная консультация — вы можете заказать её на нашем сайте.