Принудительное изменение пароля при первом входе в приложение symfony - PullRequest
2 голосов
/ 26 февраля 2020

Я пытаюсь реализовать метод, заставляющий пользователей изменять свой пароль по умолчанию при первом входе в систему в моем приложении Symfony.

В данный момент я настроил прослушиватель событий для прослушивания 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'));
        }
    }
}

В основном он проверяет наличие логического флага в пользовательском объекте, который установлен в true для новых пользователей. Он подхватывает пользователя, и метод попадает в строку RedirectResponse, но в итоге просто переходит на домашнюю страницу (поведение при входе по умолчанию).

Я не уверен, как заставить его не продолжать процесс входа в систему и перенаправить на страницу смены пароля.

Ответы [ 2 ]

2 голосов
/ 26 февраля 2020

Вы не можете сделать это, слушая InteractiveLoginEvent.

Это событие не включает в себя доступ к объекту ответа, и возвращение одного из слушателя не приведет вас никуда, поскольку никто не ждет слушателя чтобы вернуть что-либо.

Но вы можете сделать это на RequestEvent слушателе / ​​подписчике:

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')));

    }
}
0 голосов
/ 27 февраля 2020

Вот последний фрагмент кода, основанный на приведенных выше ответах и ​​справке

<?php

namespace App\EventSubscriber;

use App\Entity\User;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;

class PasswordChangeSubscriber implements EventSubscriberInterface
{
    private $security;
    private $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;
        }

        $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 User) {
            return;            
        }

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

        // if we get here, it means we need to redirect them to the password change view.
        $redirectTo = $this->urlGenerator->generate('changepassword', ['username' => $user->getUsername()]);
        if ($event->getRequest()->getRequestUri() != $redirectTo){
            $event->setResponse(new RedirectResponse($redirectTo));
        }
        return;
    }
}
...