Symfony2 расширяет DefaultAuthenticationSuccessHandler

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

namespace Pkr\BlogUserBundle\Handler;
use Doctrine\ORM\EntityManager;
use Pkr\BlogUserBundle\Service\Encoder\WpTransitionalEncoder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\Authentication\Response;

class AuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface
{

    protected $entityManager = null;
    protected $logger = null;
    protected $encoder = null;

    public function __construct(EntityManager $entityManager, LoggerInterface $logger, WpTransitionalEncoder $encoder)
    {
        $this->entityManager = $entityManager;
        $this->logger = $logger;
        $this->encoder = $encoder;
    }

    /**
    * This is called when an interactive authentication attempt succeeds. This
    * is called by authentication listeners inheriting from
    * AbstractAuthenticationListener.
    *
    * @param Request $request
    * @param TokenInterface $token
    *
    * @return Response never null
    */
    public function onAuthenticationSuccess(Request $request, TokenInterface $token)
    {
        $user = $token->getUser();
        $newPass = $request->get('_password');
        $user->setUserPassword($this->encoder->encodePassword($newPass, null));
        $this->entityManager->persist($user);
        $this->entityManager->flush();
        //do redirect
    }
}

в services.yml

services:
    pkr_blog_user.wp_transitional_encoder:
        class: "%pkr_blog_user.wp_transitional_encoder.class%"
        arguments:
            cost: "%pkr_blog_user.wp_transitional_encoder.cost%"
            logger: @logger
    pkr_blog_user.login_success_handler:
        class: Pkr\BlogUserBundle\Handler\AuthenticationSuccessHandler
        arguments:
            entity_manager: @doctrine.orm.entity_manager
            logger: @logger
            encoder: @pkr_blog_user.wp_transitional_encoder

и в security.yml

firewalls:
    dev:
        pattern:  ^/(_(profiler|wdt)|css|images|js)/
        security: false

    secured_area:
        pattern:   ^/
        anonymous: ~
        form_login:
            login_path:  pkr_blog_admin_login
            check_path:  pkr_blog_admin_login_check
            success_handler: pkr_blog_user.login_success_handler
        logout:
            path: pkr_blog_admin_logout
            target: /

Чего я пытаюсь добиться, так это просто немного изменить поведение по умолчанию, поэтому я думаю, почему бы не расширить DefaultAuthenticationSuccessHandler, добавить что-то к onSuccessHandler() и вызвать parent::onSucessHandler(). Я попытался, и проблема в том, что я понятия не имею, как добавить параметры безопасности (установленные в security.yml) в мой конструктор расширенного класса. DefaultAuthenticationSuccessHandler использует массив HttpUtils и $options:

/**
 * Constructor.
 *
 * @param HttpUtils $httpUtils
 * @param array     $options   Options for processing a successful authentication attempt.
 */
public function __construct(HttpUtils $httpUtils, array $options)
{
    $this->httpUtils   = $httpUtils;

    $this->options = array_merge(array(
        'always_use_default_target_path' => false,
        'default_target_path'            => '/',
        'login_path'                     => '/login',
        'target_path_parameter'          => '_target_path',
        'use_referer'                    => false,
    ), $options);
}

Итак, мой расширенный конструктор класса должен выглядеть так:

    // class extends DefaultAuthenticationSuccessHandler
    protected $entityManager = null;
    protected $logger = null;
    protected $encoder = null;

    public function __construct(HttpUtils $httpUtils, array $options, EntityManager $entityManager, LoggerInterface $logger, WpTransitionalEncoder $encoder)
    {
        $this->entityManager = $entityManager;
        $this->logger = $logger;
        $this->encoder = $encoder;
    }

Добавить службу HttpUtils в мой services.yml довольно просто, но что с аргументом options?

services:
    pkr_blog_user.wp_transitional_encoder:
        class: "%pkr_blog_user.wp_transitional_encoder.class%"
        arguments:
            cost: "%pkr_blog_user.wp_transitional_encoder.cost%"
            logger: @logger
    pkr_blog_user.login_success_handler:
        class: Pkr\BlogUserBundle\Handler\AuthenticationSuccessHandler
        arguments:
            httputils: @security.http_utils
            options: [] #WHAT TO ADD HERE ?
            entity_manager: @doctrine.orm.entity_manager
            logger: @logger
            encoder: @pkr_blog_user.wp_transitional_encoder

person piotrekkr    schedule 10.04.2013    source источник


Ответы (5)


Если у вас есть только один обработчик успеха/неудачи, определенный для вашего приложения, есть немного более простой способ сделать это. Вместо того, чтобы определять новую службу для success_handler и failure_handler, вы можете вместо этого переопределить security.authentication.success_handler и security.authentication.failure_handler.

Пример:

services.yml

services:
    security.authentication.success_handler:
        class:  StatSidekick\UserBundle\Handler\AuthenticationSuccessHandler
        arguments:  ["@security.http_utils", {}]
        tags:
            - { name: 'monolog.logger', channel: 'security' }

    security.authentication.failure_handler:
        class:  StatSidekick\UserBundle\Handler\AuthenticationFailureHandler
        arguments:  ["@http_kernel", "@security.http_utils", {}, "@logger"]
        tags:
            - { name: 'monolog.logger', channel: 'security' }

AuthenticationSuccessHandler.php

<?php
namespace StatSidekick\UserBundle\Handler;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler;
use Symfony\Component\Security\Http\HttpUtils;

class AuthenticationSuccessHandler extends DefaultAuthenticationSuccessHandler {

    public function __construct( HttpUtils $httpUtils, array $options ) {
        parent::__construct( $httpUtils, $options );
    }

    public function onAuthenticationSuccess( Request $request, TokenInterface $token ) {
        if( $request->isXmlHttpRequest() ) {
            $response = new JsonResponse( array( 'success' => true, 'username' => $token->getUsername() ) );
        } else {
            $response = parent::onAuthenticationSuccess( $request, $token );
        }
        return $response;
    }
}

AuthenticationFailureHandler.php

<?php
namespace StatSidekick\UserBundle\Handler;

use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler;
use Symfony\Component\Security\Http\HttpUtils;

class AuthenticationFailureHandler extends DefaultAuthenticationFailureHandler {

    public function __construct( HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options, LoggerInterface $logger = null ) {
        parent::__construct( $httpKernel, $httpUtils, $options, $logger );
    }

    public function onAuthenticationFailure( Request $request, AuthenticationException $exception ) {
        if( $request->isXmlHttpRequest() ) {
            $response = new JsonResponse( array( 'success' => false, 'message' => $exception->getMessage() ) );
        } else {
            $response = parent::onAuthenticationFailure( $request, $exception );
        }
        return $response;
    }
}

В моем случае я просто пытался настроить что-то, чтобы я мог получить ответ JSON при попытке аутентификации с использованием AJAX, но принцип тот же.

Преимущество этого подхода заключается в том, что без какой-либо дополнительной работы все параметры, которые обычно передаются в обработчики по умолчанию, должны вводиться правильно. Это происходит из-за того, как SecurityBundle\DependencyInjection\Security\Factory настроен в фреймворке:

protected function createAuthenticationSuccessHandler($container, $id, $config)
{
    ...
    $successHandler = $container->setDefinition($successHandlerId, new DefinitionDecorator('security.authentication.success_handler'));    
    $successHandler->replaceArgument(1, array_intersect_key($config, $this->defaultSuccessHandlerOptions));
    ...
}

protected function createAuthenticationFailureHandler($container, $id, $config)
{
    ...
    $failureHandler = $container->setDefinition($id, new DefinitionDecorator('security.authentication.failure_handler'));
    $failureHandler->replaceArgument(2, array_intersect_key($config, $this->defaultFailureHandlerOptions));
    ...
}

Он специально ищет security.authentication.success_handler и security.authentication.failure_handler, чтобы объединить параметры из вашей конфигурации в переданные массивы. Я уверен, что есть способ настроить что-то подобное для вашего собственного сервиса, но я еще не изучал его.

Надеюсь, это поможет.

person dmccabe    schedule 08.06.2013
comment
Спасибо, кажется, ваша идея лучше моей. Не знал, что я могу переопределить конфигурацию других пакетных служб в моем services.yml, но теперь я знаю. Спасибо - person piotrekkr; 08.06.2013
comment
Есть ли способ перенаправить в обработчике без получения ошибки Попытка вызвать перенаправление метода в классе Site\MyBundle\Handler\LoginSuccessHandler - person Jonathan; 02.10.2014
comment
Как вы пытаетесь сделать редирект? В этих обработчиках нет метода перенаправления, поэтому вместо этого вам нужно будет вернуть новый RedirectResponse. - person dmccabe; 07.10.2014
comment
Вы только что описали решение моей проблемы. Ценить! - person hosseio; 24.07.2015
comment
Начиная с Symfony 2.8 существует Guard Authenticator Service, который был создан для упрощения создания пользовательской системы аутентификации. Существует метод onAuthenticationSuccess(), который может возвращать RedirectResponse. См. учебник здесь sitepoint.com/easier-authentication-with- защита в Symfony-3 - person piotrekkr; 30.12.2015

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

поставщик/symfony/symfony/src/Symfony/Bundle/SecurityBundle/Resources/config/security_listeners.xml

Например, DefaultAuthenticationSuccessHandler регистрируется так:

    <!-- Parameter -->

    <parameter key="security.authentication.success_handler.class">Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler</parameter>

    <!-- Service -->

    <service id="security.authentication.success_handler" class="%security.authentication.success_handler.class%" abstract="true" public="false">
        <argument type="service" id="security.http_utils" />
        <argument type="collection" /> <!-- Options -->
    </service>

Итак, наконец, мы видим, что коллекция опций по умолчанию пуста!

options: {} выполнит эту работу ^^ (представьте, что коллекция представлена ​​{} в yaml)

person Sybio    schedule 10.04.2013
comment
Да это то, что видел и раньше, но значит ли это, что он всегда пуст? Что, если я установлю некоторые параметры для login_form (например, login_path или target_path_parameter) в своем security.yml? Будут ли эти параметры пустыми? - person piotrekkr; 10.04.2013
comment
Как я и подозревал, при использовании настраиваемых параметров обработчика успеха из security.yml не устанавливаются :( - person piotrekkr; 13.04.2013

Чтобы найти лучшее решение, прокрутите этот ответ до конца.

ОК, наконец-то я заработал так, как хотел. Проблема заключалась в том, что Symfony2 не передавал массив конфигурации из security.yml в конструктор, когда установлен пользовательский обработчик. Итак, что я сделал:

1) Я удалил объявление пользовательского обработчика из security.yml

firewalls:
    dev:
      pattern:  ^/(_(profiler|wdt)|css|images|js)/
      security: false

secured_area:
    pattern:   ^/
    anonymous: ~
    form_login:
        login_path:  pkr_blog_admin_login
        check_path:  pkr_blog_admin_login_check
    logout:
        path: pkr_blog_admin_logout
        target: /

2) AuthenticationSuccessHandler расширяет класс обработчика по умолчанию, перефразирует пароль пользователя и, наконец, позволяет обработчику по умолчанию делать все остальное. В конструктор добавлено два новых аргумента:

#/src/Pkr/BlogUserBundle/Handler/AuthenticationSuccessHandler.php
namespace Pkr\BlogUserBundle\Handler;
use Doctrine\ORM\EntityManager;
use Pkr\BlogUserBundle\Service\Encoder\WpTransitionalEncoder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler;
use Symfony\Component\Security\Http\Authentication\Response;
use Symfony\Component\Security\Http\HttpUtils;

class AuthenticationSuccessHandler extends DefaultAuthenticationSuccessHandler
{

    protected $entityManager = null;
    protected $logger = null;
    protected $encoder = null;

    public function __construct(
        HttpUtils $httpUtils,
        array $options,
        // new arguments below
        EntityManager $entityManager = null, # entity manager
        WpTransitionalEncoder $encoder = null
    )
    {
        $this->entityManager = $entityManager;
        $this->encoder = $encoder;
        parent::__construct($httpUtils, $options);
    }

    /**
    * This is called when an interactive authentication attempt succeeds. This
    * is called by authentication listeners inheriting from
    * AbstractAuthenticationListener.
    *
    * @param Request $request
    * @param TokenInterface $token
    *
    * @return Response never null
    */
    public function onAuthenticationSuccess(Request $request, TokenInterface $token)
    {
        $user = $token->getUser();
        if (preg_match('^\$P\$', $user->getUserPassword())) {
            $newPass = $request->get('_password');
            $user->setUserPassword($this->encoder->encodePassword($newPass, null));
            $this->entityManager->persist($user);
            $this->entityManager->flush();
        }
        return parent::onAuthenticationSuccess($request, $token);
    }
}

3) добавил и изменил некоторые параметры в моем services.yml, чтобы я мог использовать их в своем классе передачи компилятора:

#/src/Pkr/BlogUserBundle/Resources/config/services.yml
parameters:
    pkr_blog_user.wp_transitional_encoder.cost: 20
    # password encoder class
    pkr_blog_user.wp_transitional_encoder.class: Pkr\BlogUserBundle\Service\Encoder\WpTransitionalEncoder
    # authentication success handler class
    pkr_blog_user.login_success_handler.class: Pkr\BlogUserBundle\Handler\AuthenticationSuccessHandler
    # entity manager service name
    pkr_blog_user.login_success_handler.arg.entity_manager: doctrine.orm.entity_manager
    # encoder service name
    pkr_blog_user.login_success_handler.arg.encoder: pkr_blog_user.wp_transitional_encoder

services:
    pkr_blog_user.wp_transitional_encoder:
        class: "%pkr_blog_user.wp_transitional_encoder.class%"
        arguments:
            cost: "%pkr_blog_user.wp_transitional_encoder.cost%"
            logger: @logger
    pkr_blog_user.login_success_handler:
        class: "%pkr_blog_user.login_success_handler.class%"

4) создал класс передачи компилятора RehashPasswordPass, который изменяет обработчик успеха аутентификации по умолчанию и добавляет некоторые параметры в конструктор:

#/src/Pkr/BlogUserBundle/DependencyInjection/Compiler/RehashPasswordPass.php
namespace Pkr\BlogUserBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class RehashPasswordPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        if ($container->hasDefinition('security.authentication.success_handler')) {
            // definition of default success handler
            $def = $container->getDefinition('security.authentication.success_handler');
            // changing default class
            $def->setClass($container->getParameter('pkr_blog_user.login_success_handler.class'));
            $entityMngRef = new Reference(
                $container->getParameter("pkr_blog_user.login_success_handler.arg.entity_manager")
            );
            // adding entity manager as third param to constructor
            $def->addArgument($entityMngRef);
            $encoderRef = new Reference(
                $container->getParameter("pkr_blog_user.login_success_handler.arg.encoder")
            );
            // adding encoder as fourth param to constructor
            $def->addArgument($encoderRef);
        }
    }
}

5) добавлен проход компилятора в конструктор контейнеров:

#/src/Pkr/BlogUserBundle/PkrBlogUserBundle.php
namespace Pkr\BlogUserBundle;

use Pkr\BlogUserBundle\DependencyInjection\Compiler\RehashPasswordPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class PkrBlogUserBundle extends Bundle
{
    public function build(ContainerBuilder $container)
    {
        $container->addCompilerPass(new RehashPasswordPass());
    }
}

Теперь класс обработчика по умолчанию был изменен, но symfony по-прежнему будет передавать конфигурацию из security.yml в конструктор плюс два новых аргумента, добавленных компилятором.

Лучший способ

Обработчик событий как сервис с сеттерами

#/src/Pkr/BlogUserBundle/Resources/config/services.yml
parameters:
    pkr_blog_user.wp_transitional_encoder.cost: 15
    # password encoder class
    pkr_blog_user.wp_transitional_encoder.class: Pkr\BlogUserBundle\Service\Encoder\WpTransitionalEncoder
    # authentication success handler class
    pkr_blog_user.authentication_success_handler.class: Pkr\BlogUserBundle\EventHandler\AuthenticationSuccessHandler


services:
    pkr_blog_user.wp_transitional_encoder:
        class: "%pkr_blog_user.wp_transitional_encoder.class%"
        arguments:
            cost: "%pkr_blog_user.wp_transitional_encoder.cost%"
            logger: @logger

    pkr_blog_user.authentication_success_handler:
        class: "%pkr_blog_user.authentication_success_handler.class%"
        calls:
            - [ setRequest, [ @request ]]
            - [ setEntityManager, [ @doctrine.orm.entity_manager ]]
            - [ setEncoder, [ @pkr_blog_user.wp_transitional_encoder ]]
        tags:
            - { name: kernel.event_listener, event: security.authentication.success , method: handleAuthenticationSuccess }

Класс обработчика событий

# /src/Pkr/BlogUserBundle/EventHandler/AuthenticationSuccessHandler.php
namespace Pkr\BlogUserBundle\EventHandler;
use Doctrine\ORM\EntityManager;
use Pkr\BlogUserBundle\Service\Encoder\WpTransitionalEncoder;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Event\AuthenticationEvent;

class AuthenticationSuccessHandler {

    protected $entityManager = null;
    protected $encoder = null;

    public function setRequest(Request $request)
    {
        $this->request = $request;
    }

    public function setEntityManager(EntityManager $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function setEncoder(WpTransitionalEncoder $encoder)
    {
        $this->encoder = $encoder;
    }

    public function handleAuthenticationSuccess(AuthenticationEvent $event)
    {
        $token = $event->getAuthenticationToken();
        $user = $token->getUser();
        if (preg_match('^\$P\$', $user->getUserPassword())) {
            $newPass = $this->request->get('_password');
            $user->setUserPassword($this->encoder->encodePassword($newPass, null));
            $this->entityManager->persist($user);
            $this->entityManager->flush();
        }
    }

}

И все работает, компилятор не нужен. Почему я не подумал об этом с самого начала...

Ухх, он перестал работать после обновления symfony

Теперь я получаю исключение:

ScopeWideningInjectionException: Scope Widening Injection detected: The definition "pkr_blog_user.authentication_success_handler" references the service "request" which belongs to a narrower scope. Generally, it is safer to either move "pkr_blog_user.authentication_success_handler" to scope "request" or alternatively rely on the provider pattern by injecting the container itself, and requesting the service "request" each time it is needed. In rare, special cases however that might not be necessary, then you can set the reference to strict=false to get rid of this error.

Кажется, мне нужно передать полный контейнер моему сервису. Поэтому я изменил services.yml и класс обработчика событий.

#/src/Pkr/BlogUserBundle/Resources/config/services.yml
parameters:
    pkr_blog_user.wp_transitional_encoder.cost: 15
    # password encoder class
    pkr_blog_user.wp_transitional_encoder.class: Pkr\BlogUserBundle\Service\Encoder\WpTransitionalEncoder
    # authentication success handler class
    pkr_blog_user.authentication_success_handler.class: Pkr\BlogUserBundle\EventHandler\AuthenticationSuccessHandler


services:
    pkr_blog_user.wp_transitional_encoder:
        class: "%pkr_blog_user.wp_transitional_encoder.class%"
        arguments:
            secure: @security.secure_random
            cost: "%pkr_blog_user.wp_transitional_encoder.cost%"

    pkr_blog_user.authentication_success_handler:
        class: "%pkr_blog_user.authentication_success_handler.class%"
        arguments:
            container: @service_container
        tags:
            - { name: kernel.event_listener, event: security.authentication.success , method: handleAuthenticationSuccess }

И обработчик событий

# /src/Pkr/BlogUserBundle/EventHandler/AuthenticationSuccessHandler.php
namespace Pkr\BlogUserBundle\EventHandler;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Core\Event\AuthenticationEvent;

class AuthenticationSuccessHandler
{

    /**
     * @var ContainerInterface
     */
    protected $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function handleAuthenticationSuccess(AuthenticationEvent $event)
    {
        $request = $this->container->get('request');
        $em = $this->container->get('doctrine.orm.entity_manager');
        $encoder = $this->container->get('pkr_blog_user.wp_transitional_encoder');
        $token = $event->getAuthenticationToken();
        $user = $token->getUser();
        if (preg_match('/^\$P\$/', $user->getUserPassword())) {
            $newPass = $request->get('_password');
            $user->setUserPassword($encoder->encodePassword($newPass, null));
            $em->persist($user);
            $em->flush();
        }
    }

}

И снова работает.

Пока лучший способ

Приведенное выше решение было лучшим, которое я знал, пока @dmccabe не написал свое решение.

person piotrekkr    schedule 13.04.2013
comment
Как насчет внедрения @request_stack вместо всего контейнера? Позже вы можете получить текущий объект запроса, используя $requestStack->getCurrentRequest(). Кроме того, эта страница поваренной книги содержит немного информации об области видимости и сервисном контейнере. . - person Paul T. Rawkeen; 18.05.2015
comment
@PaulT.Rawkeen Вы правы, я, вероятно, мог бы передать все, что мне нужно, в качестве аргументов или вызовов методов в мою службу, не используя полный контейнер, но когда я писал свой ответ, я мало знал о внутренностях Symfony. Сегодня я бы написал свой собственный провайдер аутентификации, как здесь: symfony.com/doc/current /поваренная книга/безопасность/ - person piotrekkr; 18.05.2015
comment
Только что упоминалось, так как полезно помнить, что внедрение всего контейнера не является хорошей практикой. И кстати, мы все были не так хороши во внутренностях Symfony :). - person Paul T. Rawkeen; 19.05.2015

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

Нет, пока не будет исправлена ​​эта проблема: проблема с Symfony — [2.1][Security] Custom AuthenticationSuccessHandler

До тех пор самое простое решение - это то, что предложил @dmccabe:

Глобально перезапишите security.authentication.success_handler, что нормально, если вам не нужно иметь несколько обработчиков для нескольких брандмауэров.

Если вы это сделаете (на момент написания этой статьи), вы должны написать свой собственный поставщик аутентификации< /а>.

person flu    schedule 13.03.2014

на самом деле лучший способ сделать это - расширить обработчик аутентификации по умолчанию как службу

  authentication_handler:
      class: AppBundle\Service\AuthenticationHandler
      calls: [['setDoctrine', ['@doctrine']]]
      parent: security.authentication.success_handler
      public: false

и класс AuthenticationHandler будет выглядеть

class AuthenticationHandler extends DefaultAuthenticationSuccessHandler
{
    /**
     * @var Registry
     */
    private $doctrine;

    public function setDoctrine(Registry $doctrine)
    {
        $this->doctrine = $doctrine;
    }

    /**
     * This is called when an interactive authentication attempt succeeds. This
     * is called by authentication listeners inheriting from
     * AbstractAuthenticationListener.
     *
     * @param Request $request
     * @param TokenInterface $token
     *
     * @return Response never null
     */
    public function onAuthenticationSuccess(Request $request, TokenInterface $token)
    {
        // do whatever you like here
        // ...


        // call default success behaviour
        return parent::onAuthenticationSuccess($request, $token);
    }
}
person Bogdans    schedule 08.08.2016