September 10, 2014

September 10, 2014
2
In this article, we are going to discuss about How to manually authenticate users in Symfony 2 PHP Framework. Normally in each and every framework authencation in handled automatically. Sometimes, however you may want to perform authentication manually from the controller.

Imagine implementing automated login for a user upon visiting a URL like: /autologin/{secret}. I am not considering here the security of such a solution – you are discourage to do it this way, unless the information available for this kind of "logins" is not confidential.

Here is a fragment from my security.yml:

security:
    firewalls:
        secured_area:
            pattern:    ^/
            form_login:
                check_path: /login_check
                login_path: /login
               
The actual authentication is very straight-forward. Since I'm redirecting at the end of request, I don't even need the user to be authenticated in this action. All that is needed is to persist the information about authenticated user to the session. This means storing serialized class that implements TokenInterface. Normally this is done by Symfony framework in ContextListener. In my scenario I'm using form login that uses UsernamePasswordToken, so in short here is what I need to do:

  1. Find user
  2. Create the Token
  3. Store Token in the session

Pay attention to "secured_area" string – it matches the firewall name from the security.yml and is used to create the token and when creating a session key.

/**
 * @Route("/autologin/{secret}")
 */
public function autologinAction($secret) {
    $em = $this->getDoctrine()->getEntityManager();
    $repository = $em->getRepository('MiedzywodzieClientBundle:Reservation');
    $result = $repository->matchLoginKey($secret);
    if (!$result) {
        return $this->render('MiedzywodzieClientBundle:Default:autologin_incorrect.html.twig');
    }
    $result = $result[0]; 

    $token = new UsernamePasswordToken($result, $result->getPassword(), 'secured_area', $result->getRoles());

    $request = $this->getRequest();
    $session = $request->getSession();
    $session->set('_security_secured_area',  serialize($token));

    $router = $this->get('router');
    $url = $router->generate('miedzywodzie_client_default_dashboard');

    return $this->redirect($url);
}

2 comments:

  1. Note that session key is named according to the 'context' value of firewall, that is the same as firewall name by default. But if you have many firewalls sharing the same context, the session key will be named life '_security_' . $context, and unique for all firewalls having same context.

    ReplyDelete
  2. I would recommend using

    $token = new UsernamePasswordToken($user, '12345', $user->getUsername(), $user->getRolesAsArray());
    $this->get('security.context')->setToken($token);

    $event = new InteractiveLoginEvent($request, $token);
    $this->get("event_dispatcher")->dispatch("security.interactive_login", $event);

    ReplyDelete