问题
I'm trying to make the AJAX authentication work with FOSUserBundle.
I have created an Handler directory with a AuthenticationHandler class
:
<?php
namespace BirdOffice\UserBundle\Handler;
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
*
* @param RouterInterface $router
* @param Session $session
*/
public function __construct( RouterInterface $router, Session $session )
{
$this->router = $router;
$this->session = $session;
}
/**
* onAuthenticationSuccess
*
* @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
*
* @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' ) );
}
}
}
I have created a login Javascript function
:
function login() {
$.ajax({
type: "POST",
url: Routing.generate('check_login_ajax'),
dataType: 'json',
data: {
_username: $('#username').val(),
_password: $('#password').val(),
_remember_me: false,
_csrf_token: $('#_csrf_token').val()
}
}).done(function(data) {
console.log(data);
}).fail(function(data) {
console.log(data);
});
}
In my routingAjax.yml
, I have added the following lines to override the FOSUserBundle security route
:
check_login_ajax:
pattern: /check_login_ajax
defaults: { _controller: FOSUserBundle:Security:check }
requirements:
_method: POST
options:
expose: true
In my global security.yml
file, I have added the check_path
, success_handler
and failure_handler
parts :
firewalls:
main:
pattern: ^/
form_login:
login_path: fos_user_registration_register
check_path: check_login_ajax
success_handler: user.security.authentication_handler
failure_handler: user.security.authentication_handler
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout:
path: fos_user_security_logout
target: /
anonymous: true
My first issue is : the AJAX return this message: "Invalid CSRF token." (but I send a good one generated in PHP, maybe I missed something doing it). Here is my PHP code for it :
<?php
$csrfProvider = $this->container->get('form.csrf_provider');
$csrfToken = $csrfProvider->generateCsrfToken('popUpUser');
?>
Second issue : my login page (not the AJAX one) is not working anymore because the orignal route of FOSUserBundle login has been overwritten.
PS : I have posted a message yesterday : FOSUserBundle (login / register) + AJAX + Symfony2 but I have badly explained my problem. Sorry by advance.
回答1:
First Issue: You are sending an invalid CSRF token. In Symfony 2.3 you could generate it using {{ csrf_token('authenticate') }}
inside the template's input
's value
.
Second issue: Do not overwrite the route, simply use the original route: fos_user_security_check
.
In general: if you use an AuthenticationSuccessHandler
extending Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler
your method could look something like this:
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
if ($request->isXmlHttpRequest()) {
return new JsonResponse(array('success' => true));
}
return parent::onAuthenticationSuccess($request, $token);
}
Do something similar for an AuthenticationFailureHandler
extending Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler
.
来源:https://stackoverflow.com/questions/28678307/fosuserbundle-ajax-login-with-symfony2-routing