How to programmatically login/authenticate a user?

痞子三分冷 提交于 2019-11-26 15:06:44

Yes, you can do this via something similar to the following:

use Symfony\Component\EventDispatcher\EventDispatcher,
    Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken,
    Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

public function registerAction()
{
    // ...
    if ($this->get("request")->getMethod() == "POST")
    {
        // ... Do any password setting here etc

        $em->persist($user);
        $em->flush();

        // Here, "public" is the name of the firewall in your security.yml
        $token = new UsernamePasswordToken($user, $user->getPassword(), "public", $user->getRoles());

        // For older versions of Symfony, use security.context here
        $this->get("security.token_storage")->setToken($token);

        // Fire the login event
        // Logging the user in above the way we do it doesn't do this automatically
        $event = new InteractiveLoginEvent($request, $token);
        $this->get("event_dispatcher")->dispatch("security.interactive_login", $event);

        // maybe redirect out here
    }
}

The event firing at the end isn't automatically done when you set a token into the context, whereas it would be normally when using eg a login form or similar. Hence the reason for including it here. You may need to adjust the type of token used, depending on your use case - the UsernamePasswordToken shown above is a core token, but you can use others if required.

Edit: Adjusted the above code to explain the 'public' parameter and also add in the roles of the user into the token creation, based on Franco's comment below.

The accepted version will not work with symfony 3.3. User will be authenticated in the next request instead of the current one. The reason is that ContextListener checks for previous session existence and if not exists it will clear the security TokenStorage. The only way around this (hackish as hell) is to fake the existence of previous session by manually initialising the session (and cookie) on the current request.

Let me know if you find a better solution.

BTW I am not sure if this should be merged with the accepted solution.

private function logUserIn(User $user)
{
    $token = new UsernamePasswordToken($user, null, "common", $user->getRoles());
    $request = $this->requestStack->getMasterRequest();

    if (!$request->hasPreviousSession()) {
        $request->setSession($this->session);
        $request->getSession()->start();
        $request->cookies->set($request->getSession()->getName(), $request->getSession()->getId());
    }

    $this->tokenStorage->setToken($token);
    $this->session->set('_security_common', serialize($token));

    $event = new InteractiveLoginEvent($this->requestStack->getMasterRequest(), $token);
    $this->eventDispatcher->dispatch("security.interactive_login", $event);
}

The above code assumes that your firewall name (or shared context name) is common.

Try this : For Symfony 3 users, do not forget to make this correction to test the equality of the passwords (as the method shown to test the password on this link is not working) :

$current_password = $user->getPassword();
$user_entry_password = '_got_from_a_form';

$factory = $this->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword($user_entry_password, $user->getSalt());

if(hash_equals($current_password, $password)){
//Continue there
}

// I hash the equality process for more security

+ info : hash_equals_function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!