在 SonataMediaBundle 和 Symfony 4 中查看和下载路径的访问被拒绝
Access Denied for view and download routes in SonataMediaBundle and Symfony 4
我将 Symfony 4(更准确地说是 4.1)与 SonataAdminBundle 和 SonataMediaBundle 一起使用。
这是我的 config/routes/sonata_media.yaml
:
sonata_media_gallery:
resource: '@SonataMediaBundle/Resources/config/routing/gallery.xml'
prefix: /media/gallery
sonata_media:
resource: '@SonataMediaBundle/Resources/config/routing/media.xml'
prefix: /media
如果我运行 php bin/console debug:router
输出中有如下路由:
sonata_media_gallery_index ANY ANY ANY /media/gallery/
sonata_media_gallery_view ANY ANY ANY /media/gallery/view/{id}
sonata_media_view ANY ANY ANY /media/view/{id}/{format}
sonata_media_download ANY ANY ANY /media/download/{id}/{format}
前两条路线工作正常,但当我尝试其他两条路线时,例如:
http://localhost:8000/media/view/
http://localhost:8000/media/view/1/default
http://localhost:8000/media/download/1
http://localhost:8000/media/download/1/default
然后我总是得到 AccessDeniedException,即使我被认证为 ROLE_SUPER_ADMIN
。
错误发生在 vendor/sonata-project/media-bundle/src/Controller/MediaController.php
、downloadAction
和 viewAction
中。翻了翻源码,也没找到抛出异常的原因。
经过一番研究,我找到了罪魁祸首并解决了问题。在这里我想分享我的知识。
正如我在问题中提到的,异常是从以下位置抛出的:
vendor/sonata-project/media-bundle/src/Controller/MediaController.php
在方法 downloadAction
和 viewAction
中。这是以下 if 条件:
if (!$this->get('sonata.media.pool')->getDownloadSecurity($media)->isGranted($media, $this->getCurrentRequest())) {
throw new AccessDeniedException();
}
这两种方法都存在。这导致我 vendor/sonata-project/media-bundle/src/Provider/Pool.php
,并进一步 vendor/sonata-project/media-bundle/src/Security/RolesDownloadStrategy.php
。我在那里找不到任何错误或问题,但它让我看到了我自己配置中的另一个位置:
access_control:
- { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
- { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
我怎么会这么笨呢?路径 /media
未在 security.yml
中声明,未经身份验证的用户可以访问。对于 downloading/viewing 媒体,SonataMediaBundle
默认需要 ROLE_ADMIN
或 ROLE_SUPER_ADMIN
。
Gallery
的路由是可访问的,因为 vendor/sonata-project/media-bundle/src/Controller/GalleryController.php
不检查是否已授予访问权限。
找到罪魁祸首后,问题是选择哪种方法来解决问题
1) 更改路由前缀:
sonata_media:
resource: '@SonataMediaBundle/Resources/config/routing/media.xml'
prefix: <b>/admin</b>/media
security.yml
中声明的路径现在涵盖了media
和ROLE_ADMIN
和ROLE_SUPER_ADMIN
可以访问的路由。
缺点:如果你想在管理员之外公开媒体怎么办?如果其他角色应该能够访问它们怎么办。
2) 在security.yml
中声明一个新路径:
access_control:
- { path: ^/media/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
现在我们可以在管理员之外公开媒体。但是另一个问题仍然存在:如果其他角色需要访问媒体怎么办?
3) 在配置文件中为 SonataMedia 配置另一个下载策略:
sonata_media:
# ...
contexts:
default: # the default context is mandatory
download:
strategy: sonata.media.security.connected_strategy
mode: http
# ...
并调整路径:
access_control:
# ...
- { path: ^/media/, role: [IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED] }
# ...
现在每个登录用户都可以访问媒体。这个解决方案对我有用。
然而,这并不是一个放之四海而皆准的食谱。请查看官方文档中的章节 security 以获得更详细的信息。
我将 Symfony 4(更准确地说是 4.1)与 SonataAdminBundle 和 SonataMediaBundle 一起使用。
这是我的 config/routes/sonata_media.yaml
:
sonata_media_gallery:
resource: '@SonataMediaBundle/Resources/config/routing/gallery.xml'
prefix: /media/gallery
sonata_media:
resource: '@SonataMediaBundle/Resources/config/routing/media.xml'
prefix: /media
如果我运行 php bin/console debug:router
输出中有如下路由:
sonata_media_gallery_index ANY ANY ANY /media/gallery/
sonata_media_gallery_view ANY ANY ANY /media/gallery/view/{id}
sonata_media_view ANY ANY ANY /media/view/{id}/{format}
sonata_media_download ANY ANY ANY /media/download/{id}/{format}
前两条路线工作正常,但当我尝试其他两条路线时,例如:
http://localhost:8000/media/view/
http://localhost:8000/media/view/1/default
http://localhost:8000/media/download/1
http://localhost:8000/media/download/1/default
然后我总是得到 AccessDeniedException,即使我被认证为 ROLE_SUPER_ADMIN
。
错误发生在 vendor/sonata-project/media-bundle/src/Controller/MediaController.php
、downloadAction
和 viewAction
中。翻了翻源码,也没找到抛出异常的原因。
经过一番研究,我找到了罪魁祸首并解决了问题。在这里我想分享我的知识。
正如我在问题中提到的,异常是从以下位置抛出的:
vendor/sonata-project/media-bundle/src/Controller/MediaController.php
在方法 downloadAction
和 viewAction
中。这是以下 if 条件:
if (!$this->get('sonata.media.pool')->getDownloadSecurity($media)->isGranted($media, $this->getCurrentRequest())) {
throw new AccessDeniedException();
}
这两种方法都存在。这导致我 vendor/sonata-project/media-bundle/src/Provider/Pool.php
,并进一步 vendor/sonata-project/media-bundle/src/Security/RolesDownloadStrategy.php
。我在那里找不到任何错误或问题,但它让我看到了我自己配置中的另一个位置:
access_control:
- { path: ^/admin/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
- { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
我怎么会这么笨呢?路径 /media
未在 security.yml
中声明,未经身份验证的用户可以访问。对于 downloading/viewing 媒体,SonataMediaBundle
默认需要 ROLE_ADMIN
或 ROLE_SUPER_ADMIN
。
Gallery
的路由是可访问的,因为 vendor/sonata-project/media-bundle/src/Controller/GalleryController.php
不检查是否已授予访问权限。
找到罪魁祸首后,问题是选择哪种方法来解决问题
1) 更改路由前缀:
sonata_media:
resource: '@SonataMediaBundle/Resources/config/routing/media.xml'
prefix: <b>/admin</b>/media
security.yml
中声明的路径现在涵盖了media
和ROLE_ADMIN
和ROLE_SUPER_ADMIN
可以访问的路由。
缺点:如果你想在管理员之外公开媒体怎么办?如果其他角色应该能够访问它们怎么办。
2) 在security.yml
中声明一个新路径:
access_control:
- { path: ^/media/, role: [ROLE_ADMIN, ROLE_SONATA_ADMIN] }
现在我们可以在管理员之外公开媒体。但是另一个问题仍然存在:如果其他角色需要访问媒体怎么办?
3) 在配置文件中为 SonataMedia 配置另一个下载策略:
sonata_media:
# ...
contexts:
default: # the default context is mandatory
download:
strategy: sonata.media.security.connected_strategy
mode: http
# ...
并调整路径:
access_control:
# ...
- { path: ^/media/, role: [IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED] }
# ...
现在每个登录用户都可以访问媒体。这个解决方案对我有用。
然而,这并不是一个放之四海而皆准的食谱。请查看官方文档中的章节 security 以获得更详细的信息。