Access to the original media is not possible as the file can be private or/and unsecure for the end user. However
we still need an action to download the file from the server. To solve this issue, the SonataMediaBundle
introduces
a download strategy interface, which can be set per context and authorize the media retrieval.
Built-in security strategy:
sonata.media.security.superadmin_strategy
: DEFAULT - the user needs to have one of the following roles :
ROLE_SUPER_ADMIN
or ROLE_ADMIN
(although these roles can be configured in SonataAdminBundle)sonata.media.security.public_strategy
: no restriction, files are publicsonata.media.security.forbidden_strategy
: not possible to retrieve the original filesonata.media.security.connected_strategy
: the need to have one of the following roles :
IS_AUTHENTICATED_FULLY
or IS_AUTHENTICATED_REMEMBERED
On top of that, there is 3 download modes which can be configured to download the media. The download mode depends on the HTTP server you used:
X-Sendfile
flag (Apache + mod_xsendfile : https://tn123.org/mod_xsendfile/)X-Accel-Redirect
flag (Nginx : http://wiki.nginx.org/X-accel)Note
Some file storage abstractions might not be compatible with some specific server flag,
if you are not sure always use http
.
Note
If you use X-Sendfile
or X-Accel-Redirect
download mode, don’t forget to specify that you trust this
header by adding BinaryFileResponse::trustXSendfileTypeHeader();
in your app controller.
For the context default
the user need to be a Super Admin to retrieve the file in http
mode.
# config/packages/sonata_media.yaml
sonata_media:
db_driver: doctrine_orm
contexts:
default: # the default context is mandatory
download:
strategy: sonata.media.security.superadmin_strategy
mode: http
providers:
- sonata.media.provider.dailymotion
- sonata.media.provider.youtube
- sonata.media.provider.image
- sonata.media.provider.file
The related download route name is sonata_media_download
.
<a href="{{ path('sonata_media_download', {'id': media|sonata_urlsafeid }) }}">Download file</a>
The Strategy class must implement the DownloadStrategyInterface
which contains 2 main methods :
Let’s create the following strategy : a media can be downloaded only by the given users:
namespace Sonata\MediaBundle\Security;
use Sonata\MediaBundle\Model\MediaInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Translation\TranslatorInterface;
class UsersDownloadStrategy implements DownloadStrategyInterface
{
/**
* @var TokenStorageInterface
*/
protected $tokenStorage;
/**
* @var TranslatorInterface
*/
protected $translator;
/**
* @var array
*/
protected $users;
public function __construct(TokenStorageInterface $tokenStorage, TranslatorInterface $translator, array $users = [])
{
$this->tokenStorage = $tokenStorage;
$this->translator = $translator;
$this->users = $users;
}
public function isGranted(MediaInterface $media, Request $request)
{
return in_array($this->tokenStorage->getToken()->getUsername(), $this->users);
}
public function getDescription()
{
return $this->translator->trans(
'description.users_download_strategy',
['%users%' => '<code>'.implode('</code>, <code>', $this->users).'</code>'],
'SonataMediaBundle'
);
}
}
Let’s explain a bit :
isGranted
: the method test if granted user exists in allowed users for downloadgetDescription
: return a translated message to explain what the current strategy doesThe last important part is declaring the service.
# config/services.yaml
services:
sonata.media.security.users_strategy:
class: Sonata\MediaBundle\Security\UsersDownloadStrategy
arguments: ['@security.token_storage', '@translator', ['mozart', 'chopin']]
<!-- config/services.xml -->
<service id="sonata.media.security.users_strategy" class="Sonata\MediaBundle\Security\'UsersDownloadStrategy">
<argument type="service" id="security.token_storage"/>
<argument type="service" id="translator"/>
<argument type="collection">
<argument>mozart</argument>
<argument>chopin</argument>
</argument>
</service>
Now the service can be used with a context:
# config/packages/sonata_media.yaml
sonata_media:
db_driver: doctrine_orm
contexts:
contents:
download:
strategy: sonata.media.security.users_strategy
providers:
- sonata.media.provider.file
formats: []
Found a typo? Something is wrong in this documentation? Just fork and edit it!