Я использую Symfony 2.3 с FOSUserBundle и хочу сделать регистрационную форму с AJAX. Я нашел вопросы о SO (например, this one) и даже некоторые другие полезные сайты (Adding an AJAX Login Form to a Symfony Project), которые объяснили, как использовать FOSUserBundle с ajax.Symfony 2.3 и FOSUserBundle с AJAX продолжает бросать CSRF-ошибки
Все работает нормально, когда я отправляю форму регулярно, но используя вызов ajax, я продолжаю получать сообщение «Недопустимый токен CSRF».
Вот мои конфигурации:
Обычай AuthenticationHandler:
namespace Moodio\Bundle\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;
private $translator;
private $csrf_provider;
/**
* Constructor
*/
public function __construct(RouterInterface $router, Session $session, $translator, $csrf_provider)
{
$this->router = $router;
$this->session = $session;
$this->translator = $translator;
$this->csrf_provider = $csrf_provider;
}
/**
* onAuthenticationSuccess
*/
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;
} else {// if form login
return parent::onAuthenticationSuccess($request, $token);
}
}
/**
* onAuthenticationFailure
*
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
// if AJAX login
if ($request->isXmlHttpRequest()) {
$result = array(
'success' => false,
'message' => $this->translator->trans($exception->getMessage(), array(), 'FOSUserBundle')
); // data to return via JSON
$response = new Response(json_encode($result));
$response->headers->set('Content-Type', 'application/json');
return $response;
} else {// if form login
// set authentication exception to session
$request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception);
return new RedirectResponse($this->router->generate('fos_user_security_login'));
}
}
}
SRC/Moodio/Bundle/MainBundle/services.yml:
services:
moodio_main.security.authentication_handler:
class: Moodio\Bundle\UserBundle\Handler\AuthenticationHandler
public: false
arguments:
- @router
- @session
- @translator
- @form.csrf_provider
security.yml брандмауэров:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
success_handler: moodio_main.security.authentication_handler
failure_handler: moodio_main.security.authentication_handler
logout: true
anonymous: true
мой Javascript
$('#_submit').click(function(e){
e.preventDefault();
var frm = $('form');
$.ajax({
type : frm.attr('method'),
url : frm.attr('action'),
data : frm.serialize(),
success : function(data, status, object) {
if(data.error) $('.error').html(data.message);
},
error: function(data, status, object){
console.log(data.message);
}
});
});
Я пробовал некоторые ответы, как в this answer, но он не работает для меня. Я действительно не понимаю, почему это должно иметь значение, потому что FOSUserBundle уже создает csrf-токен и включает его в шаблон ветки с {{csrf_token}}.
В настоящее время я использую стандартные шаблоны FOSUserBundle (и добавил только строки вида js, которые мне нужны для ajax).
Одна вещь, которую я также пробовал просто проверить, работает ли проверка csrf, заключается в том, чтобы сгенерировать токен csrf в функции onAuthenticationFailure и проверить, действителен ли он только в следующей строке. В этом случае isCsrfTokenValid() возвращает true.
Когда я деактивирую csrf_provider в брандмауэре (в security.yml), я всегда получаю сообщение «Плохие учетные данные», даже несмотря на правильность учетных данных.
Я не понимаю причину, почему вы хотите внедрить логин с помощью AJAX.Потому что при входе в систему Symfony2 или любое пользовательское приложение инициирует СЕССИЮ, напишет некоторые ПРИКЛЮЧЕНИЯ, чтобы идентифицировать установленное соединение. И для этого браузера потребуется обновление. Используйте AJAX после входа в систему, но войдите в систему без использования AJAX. Если вы не разрабатываете Web-сервис для этого, вы можете использовать аутентификацию на основе токенов, не инициируя сеанс, так как все клиенты, такие как родные мобильные приложения, не будут легко запускать SESSIONS. –