Symfony2 AJAXlogin

我有一个例子,我试图创build一个使用Symfony2和FOSUserBundle的AJAXlogin。 我在我的security.yml文件中设置自己的failure_handlerfailure_handlerform_login下。

这是class级:

 class AjaxAuthenticationListener implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface { /** * This is called when an interactive authentication attempt succeeds. This * is called by authentication listeners inheriting from * AbstractAuthenticationListener. * * @see \Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener * @param Request $request * @param TokenInterface $token * @return Response the response to return */ public function onAuthenticationSuccess(Request $request, TokenInterface $token) { if ($request->isXmlHttpRequest()) { $result = array('success' => true); $response = new Response(json_encode($result)); $response->headers->set('Content-Type', 'application/json'); return $response; } } /** * This is called when an interactive authentication attempt fails. This is * called by authentication listeners inheriting from * AbstractAuthenticationListener. * * @param Request $request * @param AuthenticationException $exception * @return Response the response to return */ public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { if ($request->isXmlHttpRequest()) { $result = array('success' => false, 'message' => $exception->getMessage()); $response = new Response(json_encode($result)); $response->headers->set('Content-Type', 'application/json'); return $response; } } } 

这对处理成功和失败的AJAXlogin尝试非常有效。 但是,启用时 – 我无法通过标准格式POST方法(非AJAX)login。 我收到以下错误:

Catchable Fatal Error: Argument 1 passed to Symfony\Component\HttpKernel\Event\GetResponseEvent::setResponse() must be an instance of Symfony\Component\HttpFoundation\Response, null given

我想我的onAuthenticationSuccessonAuthenticationFailure覆盖只能被执行的XmlHttpRequests(AJAX请求),只是把执行回到原来的处理程序,如果不是。

有没有办法做到这一点?

TL; DR我希望AJAX请求的login尝试返回成功和失败的JSON响应,但我希望它不会影响通过表单POST的标准login。

大卫的回答是好的,但是对于新手来说,这是一个小小的细节 – 所以这是为了填补空白。

除了创buildAuthenticationHandler之外,还需要使用创build处理程序的包中的服务configuration将其设置为服务。 默认的bundle生成一个xml文件,但我更喜欢yml。 这是一个示例services.yml文件:

 #src/Vendor/BundleName/Resources/config/services.yml parameters: vendor_security.authentication_handler: Vendor\BundleName\Handler\AuthenticationHandler services: authentication_handler: class: %vendor_security.authentication_handler% arguments: [@router] tags: - { name: 'monolog.logger', channel: 'security' } 

您需要修改DependencyInjection捆绑包扩展来使用yml而不是xml,如下所示:

 #src/Vendor/BundleName/DependencyInjection/BundleExtension.php $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); 

然后在应用程序的安全configuration中,设置对刚定义的authentication_handler服务的引用:

 # app/config/security.yml security: firewalls: secured_area: pattern: ^/ anonymous: ~ form_login: login_path: /login check_path: /login_check success_handler: authentication_handler failure_handler: authentication_handler 
 namespace YourVendor\UserBundle\Handler; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Bundle\FrameworkBundle\Routing\Router; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; class AuthenticationHandler implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface { private $router; public function __construct(Router $router) { $this->router = $router; } public function onAuthenticationSuccess(Request $request, TokenInterface $token) { if ($request->isXmlHttpRequest()) { // Handle XHR here } else { // If the user tried to access a protected resource and was forces to login // redirect him back to that resource if ($targetPath = $request->getSession()->get('_security.target_path')) { $url = $targetPath; } else { // Otherwise, redirect him to wherever you want $url = $this->router->generate('user_view', array( 'nickname' => $token->getUser()->getNickname() )); } return new RedirectResponse($url); } } public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { if ($request->isXmlHttpRequest()) { // Handle XHR here } else { // Create a flash message with the authentication error message $request->getSession()->setFlash('error', $exception->getMessage()); $url = $this->router->generate('user_login'); return new RedirectResponse($url); } } } 

如果您想要FOS UserBundle表单错误支持,您必须使用:

 $request->getSession()->set(SecurityContext::AUTHENTICATION_ERROR, $exception); 

代替:

 $request->getSession()->setFlash('error', $exception->getMessage()); 

在第一个答案。

(当然记得关于头文件:使用Symfony \ Component \ Security \ Core \ SecurityContext;)

我完全用javascript处理了这个:

 if($('a.login').length > 0) { // if login button shows up (only if logged out) var formDialog = new MyAppLib.AjaxFormDialog({ // create a new ajax dialog, which loads the loginpage title: 'Login', url: $('a.login').attr('href'), formId: '#login-form', successCallback: function(nullvalue, dialog) { // when the ajax request is finished, look for a login error. if no error shows up -> reload the current page if(dialog.find('.error').length == 0) { $('.ui-dialog-content').slideUp(); window.location.reload(); } } }); $('a.login').click(function(){ formDialog.show(); return false; }); } 

这里是AjaxFormDialog类。 不幸的是,我现在还没有将它移植到一个jQuery插件… https://gist.github.com/1601803

您必须在两种情况下(Ajax或不)返回一个Response对象。 添加一个“别”,你很好去。

默认的实现是:

 $response = $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request)); 

AbstractAuthenticationListener::onSuccess

我为新用户提供了一个小包,提供一个AJAXlogin表单: https : //github.com/Divi/AjaxLoginBundle

你只需要在security.yml中用ajax_form_login代替form_loginauthentication。

随意在Github问题跟踪器中build议新function!

这可能不是OP所要求的,但我遇到了这个问题,并认为其他人可能会遇到和我一样的问题。

对于那些正在使用接受的答案中描述的方法实现AJAXlogin的人,以及谁也使用AngularJS来执行AJAX请求,默认情况下这不起作用。 Angular的$http没有设置Symfony在调用$request->isXmlHttpRequest()方法时使用的头文件。 为了使用这个方法,你需要在Angular请求中设置适当的头文件。 这是我所做的解决这个问题:

 $http({ method : 'POST', url : {{ path('login_check') }}, data : data, headers: {'X-Requested-With': 'XMLHttpRequest'} }) 

在使用此方法之前,请注意,此标题对于CORS不起作用。 看到这个问题