Symfony2的:AJAX请求:如何在需要时处理身份验证?身份验证、如何在、AJAX

2023-09-10 18:26:35 作者:张艺兴(LAY)

使用Symfony2的我已经实现了AJAX的行动来管理一些书签在我的应用程序(添加/删除)。因此,用户需要被验证以继续。 我有一个解决方案,重定向用户到登录页面,但我认为这将是更好地使用一个事件来处理这个重定向。

Using Symfony2 I have implemented an AJAX action to manage some bookmarks (add/remove) in my application. So a user needs to be authenticated to proceed. I have a solution that redirects user to login page but I think it would be better to use an event to handle this redirection.

实际的解决方案:

检查用户的认证的完成同样的方式,在FOSUserBundle

Check of user's authentication is done the same way that in 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       
                }
            },
        });
    }); 
});

其他解决方案? :

为了不验证在控制器级别的用户进行身份验证,我会保护我的路线在安全配置文件:

In order not verify at controller level that user is authenticated, I would protect my route in security configuration file :

安全性:的

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的内部重定向吨登录页面,你可以与萤火虫看到:

Basically, when trying this solution, Symfony2 redirects internally ton login page as you can see with Firebug :

所以,我的问题是:

在不Symfony2中抛出一个事件或重新定向之前,一个异常?这将允许使用监听器来捕捉事件,并设置例如JSON响应? 在这种情况下,应该是什么样的反应prepared?类似的东西使用HTTP标头code像302(或别的什么)我的第一个解决方案。如何在AJAX一级处理呢?

我可以看到一些基于异常事件的解决方案,但我想抛出异常,在控制器的水平是必要的,这正是我想避免的。下面是一个例子:

I could see some exception event solution based but I think it is necessary to throw the exception at controller level and this is what I would like to avoid. Here is an example :

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

推荐答案

下面是一个解决方案(见here了解详细信息):

Here is a solution (see here for details) :

安全:

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 (i.e. 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);                        
                }               
            },
        });
    }); 
});