Force password change on first login in symfony app

MartynW :

I am trying to implement a method to force users to change their default password on their first login in my Symfony application.

At the moment I have set up an event listener to listen for the InteractiveLogin event.

namespace App\EventListener;

use App\Entity\User;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

class LoginListener
{

    private $urlGenerator;

    public function __construct(UrlGeneratorInterface $urlGenerator)
    {
        $this->urlGenerator = $urlGenerator;
    }

    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {
        // Get the User entity.
        $user = $event->getAuthenticationToken()->getUser();
        if ($user->getForcepasswordchange()) {
            return new RedirectResponse($this->urlGenerator->generate('force_password_change'));
        }
    }
}

It basically checks for a boolean flag in the user entity that is set to true for new users. It picks up the user and the method gets to the RedirectResponse line but it just ends up going to the homepage (the default login behaviour).

I am not sure how to force it to not continue the login process and redirect to my password change page.

yivi :

You can't do this listening to the InteractiveLoginEvent.

This event does not include access to the response object, and returning one from the listener won't get you nowhere, since no one is waiting for the listener to return anything.

But you could do this on a RequestEvent listener/subscriber:

class PasswordChangeSubscriber implements EventSubscriberInterface
{
    private Security              $security;
    private UrlGeneratorInterface $urlGenerator;

    public function __construct(Security $security, UrlGeneratorInterface $urlGenerator)
    {
        $this->security     = $security;
        $this->urlGenerator = $urlGenerator;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::REQUEST => [['forcePasswordChange', 0]],
        ];
    }

    public function forcePasswordChange(RequestEvent $event): void
    {

        // only deal with the main request, disregard subrequests
        if (!$event->isMasterRequest()) {
            return;
        }

        // if we are visiting the password change route, no need to redirect
        // otherwise we'd create an infinite redirection loop
        if ($event->getRequest()->get('_route') === 'force_password_change') {  
            return;
        }

        $user    = $this->security->getUser();
        // if you do not have a valid user, it means it's not an authenticated request, so it's not our concern
        if (!$user instanceof YourUserClass) {
            return;            
        }

        // if it's not their first login, and they do not need to change their password, move on
        if (!$user->isPasswordChangeRequired()) {
            return;
        }

        // if we get here, it means we need to redirect them to the password change view.
        $event->setResponse(new RedirectResponse($this->urlGenerator->generate('force_password_change')));

    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=11484&siteId=1