If you only have one success / failure handler defined for your application, there's a slightly easier way to do this. Rather than define a new service for the success_handler
and failure_handler
, you can override security.authentication.success_handler
and security.authentication.failure_handler
instead.
Example:
services.yml
services:
security.authentication.success_handler:
class: StatSidekickUserBundleHandlerAuthenticationSuccessHandler
arguments: ["@security.http_utils", {}]
tags:
- { name: 'monolog.logger', channel: 'security' }
security.authentication.failure_handler:
class: StatSidekickUserBundleHandlerAuthenticationFailureHandler
arguments: ["@http_kernel", "@security.http_utils", {}, "@logger"]
tags:
- { name: 'monolog.logger', channel: 'security' }
AuthenticationSuccessHandler.php
<?php
namespace StatSidekickUserBundleHandler;
use SymfonyComponentHttpFoundationJsonResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;
use SymfonyComponentSecurityHttpAuthenticationDefaultAuthenticationSuccessHandler;
use SymfonyComponentSecurityHttpHttpUtils;
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 StatSidekickUserBundleHandler;
use PsrLogLoggerInterface;
use SymfonyComponentHttpFoundationJsonResponse;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpKernelHttpKernelInterface;
use SymfonyComponentSecurityCoreExceptionAuthenticationException;
use SymfonyComponentSecurityHttpAuthenticationDefaultAuthenticationFailureHandler;
use SymfonyComponentSecurityHttpHttpUtils;
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;
}
}
In my case, I was just trying to set something up so that I could get a JSON response when I try to authenticate using AJAX, but the principle is the same.
The benefit of this approach is that without any additional work, all of the options that are normally passed into the default handlers should get injected correctly. This happens because of how SecurityBundleDependencyInjectionSecurityFactory is setup in the framework:
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));
...
}
It specifically looks for security.authentication.success_handler
and security.authentication.failure_handler
in order to merge options from your config into the arrays passed in. I'm sure there's a way to setup something similar for your own service, but I haven't looked into it yet.
Hope that helps.