Решил настроить Symfony так, чтобы фаервол работал в ней от корня, но при этом были доступны страницы авторизации.
Первым делом, хочется сказать, что сделать это нельзя с помощью обычных настроек в app/config/security.yml А с помощью наследования от Symfony\Bundle\FrameworkBundle\Controller\Controller у меня не получилось, да и не красиво это. А можно это сделать с помощью написания своего ControllerListener-а.
Давайте по шагам
1. Создаем файл по адресу src/Helper/ControllerListener.php
2. С содержимым:
<?php
namespace Helper;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
/**
* класс проверяющий права доступа пользователя и в будущем может что-то еще
* см. http://www.ricardclau.com/2011/08/kohana-style-before-and-after-methods-in-symfony2/
* Class ControllerListener
* @package Helper
* @throws AccessDeniedException in case token is not valid
*/
class ControllerListener
{
/**
* This variable gets kernel container object
*
* @var ContainerInterface
*/
protected $container;
/**
* This constructor method injects a Container object in order to have access to YML bundle configuration inside the listener
*
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* This method handles kernelControllerEvent checking if token is valid
*
* @param FilterControllerEvent $event
* @throws AccessDeniedException
*/
public function onKernelController(FilterControllerEvent $event)
{
$controller = $event->getController();
/**
* $controller passed can be either a class or a Closure. This is not usual in Symfony2 but it may happien.
* If it is a class, it comes in array format, so this works as @stof said
* @see https://github.com/symfony/symfony/issues/1975
*/
if (!is_array($controller)) {
// not a object but a different kind of callable. Do nothing
return;
}
/** @var Controller $controllerObject */
$controllerObject = $controller[0];
if($controllerObject instanceof Controller){
// если это класс авторизации - проверять доступ не нужно
if($controllerObject instanceof \Acme\AuthBundle\Controller\DefaultController){
return ;
}
if(!$controllerObject->getUser()){// если пользователь авторизован
throw new AccessDeniedException();// это вызов скажет фаерволу, что пользователь не авторизован
}
}
}
}
3. Чтобы выше созданный класс заработал, добавим его как листенер в файл app/config/config.yml:
services:
controller_listener:
class: Helper\ControllerListener
arguments: [@service_container]
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
Готово.
p.s. если в результате Ваших настроек Вы получаете ошибку:
The controller must return a response (null given). Did you forget to add a return statement somewhere in your controller?
значит проблема вовсе не в бандле SensioFrameworkExtraBundle, как пишут некоторые. Если подебажить и подумать, оказывается, что в фаерволе необходимо указывать form_login cо всеми параметрами типа login_path, check_path и т.п.
Комментарии