Symfony2 AJAX Login

前端 未结 7 2730
谎友^
谎友^ 2020-11-28 01:42

I have an example where I am trying to create an AJAX login using Symfony2 and FOSUserBundle. I am setting my own success_handler and failure_handler

相关标签:
7条回答
  • 2020-11-28 02:30

    David's answer is good, but it's lacking a little detail for newbs - so this is to fill in the blanks.

    In addition to creating the AuthenticationHandler you'll need to set it up as a service using the service configuration in the bundle where you created the handler. The default bundle generation creates an xml file, but I prefer yml. Here's an example services.yml file:

    #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' }
    

    You'd need to modify the DependencyInjection bundle extension to use yml instead of xml like so:

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

    Then in your app's security configuration you set up the references to the authentication_handler service you just defined:

    # 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
    
    0 讨论(0)
  • 2020-11-28 02:30

    If you want the FOS UserBundle form error support, you must use:

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

    instead of:

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

    In the first answer.

    (of course remember about the header: use Symfony\Component\Security\Core\SecurityContext;)

    0 讨论(0)
  • 2020-11-28 02:41

    I handled this entirely with 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;
            });
        }
    

    Here is the AjaxFormDialog class. Unfortunately I have not ported it to a jQuery plugin by now... https://gist.github.com/1601803

    0 讨论(0)
  • 2020-11-28 02:41

    You must return a Response object in both case (Ajax or not). Add an `else' and you're good to go.

    The default implementation is:

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

    in AbstractAuthenticationListener::onSuccess

    0 讨论(0)
  • 2020-11-28 02:42
    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);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 02:43

    This may not be what the OP asked, but I came across this question, and thought others might have the same problem that I did.

    For those who are implementing an AJAX login using the method that is described in the accepted answer and who are ALSO using AngularJS to perform the AJAX request, this won't work by default. Angular's $http does not set the headers that Symfony is using when calling the $request->isXmlHttpRequest() method. In order to use this method, you need to set the appropriate header in the Angular request. This is what I did to get around the problem:

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

    Before you use this method, be aware that this header does not work well with CORS. See this question

    0 讨论(0)
提交回复
热议问题