2015-05-12 2 views
0

Я использую 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), я всегда получаю сообщение «Плохие учетные данные», даже несмотря на правильность учетных данных.

+0

Я не понимаю причину, почему вы хотите внедрить логин с помощью AJAX.Потому что при входе в систему Symfony2 или любое пользовательское приложение инициирует СЕССИЮ, напишет некоторые ПРИКЛЮЧЕНИЯ, чтобы идентифицировать установленное соединение. И для этого браузера потребуется обновление. Используйте AJAX после входа в систему, но войдите в систему без использования AJAX. Если вы не разрабатываете Web-сервис для этого, вы можете использовать аутентификацию на основе токенов, не инициируя сеанс, так как все клиенты, такие как родные мобильные приложения, не будут легко запускать SESSIONS. –

ответ

0

я, наконец, мог бы решить мою проблему:

Я нашел Divi-AjaxLoginBundle, который работает как шарм. Я не уверен, в чем проблема, потому что у меня на самом деле были те же AuthenticationHandlers, что и этот комплект, но есть также файлы в папке DependencyInjection, которые, возможно, сделали эту работу.

Спасибо всем, кто пытался мне помочь.

+0

ОК, я понял, это была действительно глупая ошибка. У jquery.js, который мы используем, есть некоторые странные изменения в нем (возможно, их коллега), которые повлияли на запросы ajax. С официальной версией jquery все работает нормально. – MarkusS

0

Если вы используете самую последнюю версию FOSUserBundle, поставщик csrf изменил на security.csrf.token_manager. Ваша форма может генерировать токен с помощью form.csrf_provider, а FOSUB может использовать другой. Либо:

  1. явно установить FOSUserBundle зависимость 1.2 или 1.3, а не DEV-мастер
  2. вручную установить поставщика CSRF в соответствующую службу.

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