简体   繁体   English

首次登录 symfony 应用程序时强制更改密码

[英]Force password change on first login in symfony app

I am trying to implement a method to force users to change their default password on their first login in my Symfony application.我正在尝试实现一种方法来强制用户在他们第一次登录我的 Symfony 应用程序时更改他们的默认密码。

At the moment I have set up an event listener to listen for the InteractiveLogin event.目前我已经设置了一个事件监听器来监听InteractiveLogin事件。

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.它基本上检查用户实体中的布尔标志,该标志对于新用户设置为 true。 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).它获取用户,并且该方法进入RedirectResponse行,但它最终会进入主页(默认登录行为)。

I am not sure how to force it to not continue the login process and redirect to my password change page.我不确定如何强制它不继续登录过程并重定向到我的密码更改页面。

You can't do this listening to the InteractiveLoginEvent .你不能这样做听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:但是您可以在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')));

    }
}

Here is the final piece of code based on the above answers and help这是基于上述答案和帮助的最后一段代码

<?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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM