Symfony 2 FOS User Bundle Bootstrap modal AJAX Login

16,478

Solution 1

I have found the solution. Here is what I added to my javascript,

<script>
    $(document).ready(function(){
        $('#_submit').click(function(e){
            e.preventDefault();
            $.ajax({
                type        : $('form').attr( 'method' ),
                url         : '{{ path("fos_user_security_check") }}',
                data        : $('form').serialize(),
                dataType    : "json",
                success     : function(data, status, object) {
                    if(data.error) $('.error').html(data.message);
                },
                error: function(data, status, object){
                    console.log(data.message);
                }
            });
        });
    });
</script>

And here is my onAuthenticationFailure method from my handler,

public function onAuthenticationFailure(Request $request, AuthenticationException $exception) {
    $result = array(
        'success' => false, 
        'function' => 'onAuthenticationFailure', 
        'error' => true, 
        'message' => $this->translator->trans($exception->getMessage(), array(), 'FOSUserBundle')
    );
    $response = new Response(json_encode($result));
    $response->headers->set('Content-Type', 'application/json');

    return $response;
}

I think that it was the URL from my Ajax method that was wrong. Thank you for your advices.

Solution 2

I guess what youre looking for is this: Symfony2 ajax login.

your javascript would look sth. like this:

$('#_submit').click(function(e){
        e.preventDefault();
        $.ajax({
            type        : $('form').attr( 'method' ),
            url         : $('form').attr( 'action' ),
            data        : $('form').serialize(),
            success     : function(data, status, object) {
                if (data.sucess == false) {
                    $('.modal-body').prepend('<div />').html(data.message);
                } else {
                    window.location.href = data.targetUrl;
                }
            }
    });

You also have to modify the isXmlHttpRequest-part of your onAuthenticationSuccess-Method:

[...]
if ($request->isXmlHttpRequest()) {
            $targetUrl = $request->getSession()->get('_security.target_path');
            $result = array('success' => true, 'targetUrl' => targetUrl );
            $response = new Response(json_encode($result));
            $response->headers->set('Content-Type', 'application/json');
            return $response;
        }
[...]
Share:
16,478

Related videos on Youtube

Valentin
Author by

Valentin

Senior API Developer at Telus / CTO of Speakbox

Updated on June 04, 2022

Comments

  • Valentin
    Valentin almost 2 years

    Has anyone already built a login form inside a Bootstrap modal with Symfony 2 and FOS User Bundle ?

    Here is what I have now :

    src/Webibli/UserBundle/Resources/config/service.yml

    authentication_handler:
        class:        Webibli\UserBundle\Handler\AuthenticationHandler
        arguments:    [@router, @security.context, @fos_user.user_manager, @service_container]
    

    app/config/security.yml

    form_login:
        provider: fos_userbundle
        success_handler: authentication_handler
        failure_handler: authentication_handler
    

    src/Webibli/UserBundle/Handler/AuthenticationHandler.php

    <?php
    
    namespace Webibli\UserBundle\Handler;
    
    use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
    use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
    use Symfony\Component\Routing\RouterInterface;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\HttpFoundation\RedirectResponse;
    use Symfony\Component\Routing\Router;
    use Symfony\Component\Security\Core\SecurityContext;
    use Symfony\Component\Security\Core\Exception\AuthenticationException;
    
    
    class AuthenticationHandler implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface
    {
    
        protected $router;
        protected $security;
        protected $userManager;
        protected $service_container;
    
        public function __construct(RouterInterface $router, SecurityContext $security, $userManager, $service_container)
        {
            $this->router = $router;
            $this->security = $security;
            $this->userManager = $userManager;
            $this->service_container = $service_container;
    
        }
        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;
            }
            else {
                // Create a flash message with the authentication error message
                $request->getSession()->getFlashBag()->set('error', $exception->getMessage());
                $url = $this->router->generate('fos_user_security_login');
    
                return new RedirectResponse($url);
            }
    
            return new RedirectResponse($this->router->generate('anag_new')); 
        } 
        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;
            }
            return new Response();
        }
    }
    

    And here is the Twig view I am loading into my Bootstrap modal:

    {% extends 'UserBundle::layout.html.twig' %}
    {% trans_default_domain 'FOSUserBundle' %}
    {% block user_content %}
    <script>
        $('#_submit').click(function(e){
            e.preventDefault();
            $.ajax({
                type        : $('form').attr( 'method' ),
                url         : $('form').attr( 'action' ),
                data        : $('form').serialize(),
                success     : function(data, status, object) {
                    console.log( status );
                    console.log( object.responseText );
                }
        });
    });
    </script>
    <div class="modal-dialog">
        <div class="modal-content">
            <form action="{{ path("fos_user_security_check") }}" method="post" role="form" data-async data-target="#rating-modal" class="text-left">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title">{{ 'layout.login'|trans }}</h4>
            </div>
            <div class="modal-body">
                {% if error %}
                    <div>{{ error|trans }}</div>
                {% endif %}
                <input type="hidden" name="_csrf_token" value="{{ csrf_token }}" />
                <div class="form-group container">
                    <label for="email">{{ 'security.login.username_email'|trans }}</label>
                    <input type="text" class="form-control" id="username" name="_username" value="{{ last_username }}" required="required" placeholder="[email protected]">
                </div>
                <div class="form-group container">
                    <label for="password">{{ 'security.login.password'|trans }}</label><br />
                    <input type="password" id="password" name="_password" required="required" class="form-control" placeholder="********">
                </div>
                <div class="form-group container">
                    <label for="remember_me">
                        <input type="checkbox" id="remember_me" name="_remember_me" value="on" />
                        {{ 'security.login.remember_me'|trans }}
                    </label>
                </div>
            </div>
            <div class="modal-footer">
              <input type="submit" id="_submit" name="_submit" value="{{ 'security.login.submit'|trans }}" class="btn btn-primary">
            </div>
        </form>
    </div>
    </div>
    {% endblock %}
    

    The login form is working perfectly fine without AJAX. I am just trying to get error on my form in the modal if there is a problem, or redirect the user if the login is successful.

    Can anyone explain how to achieve that?

  • Valentin
    Valentin over 10 years
    Seems like a good start. I tried your implementation, the only problem is that I always have a success with the value "true", never false...
  • Andy Rosslau
    Andy Rosslau over 10 years
    fine :) would you mind to flag my answer as solution, anyway?