How can I get a json object being returned after the successful authorization instead of redirecting to the default path? I'm using Symfony 3.0.1 and I don't use FOSBundle.
My login controller looks like this:
class ClientLoginController extends Controller
{
/**
* @Route("/login", name="login")
*/
public function loginAction(Request $request)
{
$client = new Client();
$form = $this->createForm(ClientLoginType::class, $client);
$form->handleRequest($request);
$authenticationUtils = $this->get('security.authentication_utils');
$lastEmail = $authenticationUtils->getLastUsername();
$error = $authenticationUtils->getLastAuthenticationError();
if ($form->isSubmitted() && $form->isValid())
{
return new JsonResponse(
array(
'message' => 'Success! You're authorised!',
'result' => $this->renderView('SymfonyBundle::client/success.html.twig')
), 200);
}
return $this->render(
'SymfonyBundle::security/security.html.twig',
array(
'login_form' => $form->createView(),
'error' => $error,
'last_email' => $lastEmail,
)
);
}
}
And the login part in security.yml config looks like this:
form_login:
login_path: login
check_path: login
username_parameter: _email
failure_forward: false
default_target_path: login
csrf_token_generator: security.csrf.token_manager
Thank you in advance!
When you post the login form to the URL set as check_path
in the security config, symfony will intercept the request by a listener and handle user authentication internally and than redirect to a page based on the configuration. The code inside if ($form->isSubmitted() && $form->isValid())
will never be called actually because of this.
You have multiple options to override this behaviour:
AuthenticationEvents::AUTHENTICATION_SUCCESS
and AuthenticationEvents::AUTHENTICATION_FAILURE
eventsThe linked blog post above for the authentication handler case is exactly what you need. I just copy paste the code here, you can find more details in the post.
Create the handler class:
// AuthenticationHandler.php
namespace path\to\your\class;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
class AuthenticationHandler implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface
{
private $router;
private $session;
/**
* Constructor
*
* @author Joe Sexton <joe@webtipblog.com>
* @param RouterInterface $router
* @param Session $session
*/
public function __construct( RouterInterface $router, Session $session )
{
$this->router = $router;
$this->session = $session;
}
/**
* onAuthenticationSuccess
*
* @author Joe Sexton <joe@webtipblog.com>
* @param Request $request
* @param TokenInterface $token
* @return Response
*/
public function onAuthenticationSuccess( Request $request, TokenInterface $token )
{
// if AJAX login
if ( $request->isXmlHttpRequest() ) {
$array = array( 'success' => true ); // data to return via JSON
$response = new Response( json_encode( $array ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
// if form login
} else {
if ( $this->session->get('_security.main.target_path' ) ) {
$url = $this->session->get( '_security.main.target_path' );
} else {
$url = $this->router->generate( 'home_page' );
} // end if
return new RedirectResponse( $url );
}
}
/**
* onAuthenticationFailure
*
* @author Joe Sexton <joe@webtipblog.com>
* @param Request $request
* @param AuthenticationException $exception
* @return Response
*/
public function onAuthenticationFailure( Request $request, AuthenticationException $exception )
{
// if AJAX login
if ( $request->isXmlHttpRequest() ) {
$array = array( 'success' => false, 'message' => $exception->getMessage() ); // data to return via JSON
$response = new Response( json_encode( $array ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
// if form login
} else {
// set authentication exception to session
$request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception);
return new RedirectResponse( $this->router->generate( 'login_route' ) );
}
}
}
Register it as a service and set is as the success and failure handler of the used firewall:
# Resources/config/services.yml
acme.security.authentication_handler:
class: path\to\your\class\AuthenticationHandler
public: false
arguments:
- @router
- @session
# app/config/security.yml
security:
firewalls:
main:
form_login:
check_path: security_check_route
success_handler: acme.security.authentication_handler
failure_handler: acme.security.authentication_handler