Symfony2:AJAX请求:如何在需要时处理身份validation?

使用Symfony2我已经实现了一个AJAX操作来管理我的应用程序中的一些书签(添加/删除)。 因此,用户需要进行身份validation才能继续。 我有一个解决方案,将用户重定向到登录页面,但我认为最好使用事件来处理此重定向。

实际解决方案

检查用户的身份validation的方式与FOSUserBundle中的方式相同。

路由:

fbn_guide_manage_bookmark: path: /bookmark/manage defaults: { _controller: FBNGuideBundle:Guide:managebookmark } options: expose: true requirements: _method: POST 

控制器:

 public function manageBookmarkAction(Request $request) { if ($request->isXmlHttpRequest()) { $user = $this->getUser(); if (!is_object($user) || !$user instanceof UserInterface) { return new JsonResponse(array('status' => 'login')); } // DO THE STUFF } } 

jQuery:

 $(function() { $('#bookmark').click(function() { $.ajax({ type: 'POST', url: Routing.generate('fbn_guide_manage_bookmark'), data : xxxx, // SOME DATA success: function(data) { if (data.status == 'login') { var redirect = Routing.generate('fos_user_security_login'); window.location.replace(redirect); } else { // DO THE STUFF } }, }); }); }); 

其他方案?

为了不在控制器级validation用户是否经过身份validation,我会在安全配置文件中保护我的路由:

安全:

 security: access_control: - { path: ^/(fr|en)/bookmark/manage, role: ROLE_USER } 

控制器:

 public function manageBookmarkAction(Request $request) { if ($request->isXmlHttpRequest()) { $user = $this->getUser(); // THIS VERIFCATION SHOULD NOW BE REMOVED /* if (!is_object($user) || !$user instanceof UserInterface) { return new JsonResponse(array('status' => 'login')); } */ // DO THE STUFF } } 

基本上,在尝试此解决方案时,Symfony2重定向内部登录页面,您可以使用Firebug查看:

在此处输入图像描述

所以我的问题是:

  1. Symfony2在重定向之前是抛出事件还是exception? 这将允许使用侦听器来捕获事件并设置JSON响应,例如?
  2. 在这种情况下,应该准备什么样的响应? 像我的第一个使用HTTP标头代码(如302)或其他东西的解决方案。 如何在AJAX级别处理此问题?

我可以看到一些exception事件解决方案,但我认为有必要在控制器级别抛出exception,这是我想避免的。 这是一个例子:

https://github.com/winzou/AssoManager/blob/master/src/Asso/AMBundle/Listener/AjaxAuthenticationListener.php

这是一个解决方案(详见此处 ):

安全:

 firewalls: main: pattern: ^/ anonymous: true provider: fos_userbundle entry_point: fbn_user.login_entry_point #... access_control: - { path: ^/(fr|en)/bookmark/manage, role: ROLE_USER } 

服务 :

 services: fbn_user.login_entry_point: class: FBN\UserBundle\EventListener\LoginEntryPoint arguments: [ @router ] 

服务类:

 namespace FBN\UserBundle\EventListener; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\JsonResponse; /** * When the user is not authenticated at all (ie when the security context has no token yet), * the firewall's entry point will be called to start() the authentication process. */ class LoginEntryPoint implements AuthenticationEntryPointInterface { protected $router; public function __construct($router) { $this->router = $router; } /** * This method receives the current Request object and the exception by which the exception * listener was triggered. * * The method should return a Response object */ public function start(Request $request, AuthenticationException $authException = null) { if ($request->isXmlHttpRequest()) { return new JsonResponse('',401); } return new RedirectResponse($this->router->generate('fos_user_security_login')); } } 

jQuery:

 $(function() { $('#bookmark').click(function() { // DATA PROCESSING $.ajax({ type: 'POST', url: Routing.generate('fbn_guide_manage_bookmark'), data : xxxx, // SOME DATA, success: function(data) { // DO THE STUFF }, error: function(jqXHR, textStatus, errorThrown) { switch (jqXHR.status) { case 401: var redirectUrl = Routing.generate('fos_user_security_login'); window.location.replace(redirectUrl); break; case 403: // (Invalid CSRF token for example) // Reload page from server window.location.reload(true); } }, }); }); }); 
  1. 是的,可以按照以下答案中的描述处理事件: https : //stackoverflow.com/a/9182954/982075

  2. 使用HTTP状态码401(未授权)或403(禁止)

    您可以使用jquery中的error函数来处理响应

     $.ajax({ type: 'POST', url: Routing.generate('fbn_guide_manage_bookmark'), data : xxxx, // SOME DATA error: function() { alert("Your session has expired"); } }); 

我为Symf4解决了这个问题(不应该与其他人有很大不同)。 exception侦听器将在重定向发生之前为POST提供JSON响应。 在其他情况下,它仍将像往常一样重定向。 您可以进一步自定义如何处理侦听器中的exception。

================================================== =====

 sevices: exeption_listener: class: Path\To\Listener\ExeptionListener arguments: ['@security.token_storage'] tags: - { name: kernel.event_listener, event: kernel.exception } 

================================================== =====

 Listener/ExeptionListener.php  array( array('processException', 10), array('logException', 0), array('notifyException', -10), ) ); } public function processException(GetResponseForExceptionEvent $event) { // ... if (!$event->isMasterRequest()) { // don't do anything if it's not the master request return; } $request = $event->getRequest(); if( $request->getMethod() === 'POST' ){ $event->setResponse(new JsonResponse(array('error'=>$event->getException()->getMessage()), 403)); } } public function logException(GetResponseForExceptionEvent $event) { // ... } public function notifyException(GetResponseForExceptionEvent $event) { // ... } }