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

Posted

技术标签:

【中文标题】首次登录 symfony 应用程序时强制更改密码【英文标题】:Force password change on first login in symfony app 【发布时间】:2020-06-09 17:38:54 【问题描述】:

我正在尝试实现一种方法来强制用户在第一次登录我的 Symfony 应用程序时更改他们的默认密码。

目前我已经设置了一个事件监听器来监听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'));
        
    

它基本上检查用户实体中的布尔标志,该标志为新用户设置为真。它获取用户并且该方法到达RedirectResponse 行,但最终只是转到主页(默认登录行为)。

我不确定如何强制它不继续登录过程并重定向到我的密码更改页面。

【问题讨论】:

您可以进行登录计数。如果登录计数 = 1,则强制更改密码。您还可以合并自登录以来的日期,并强制用户在…… 3 个月后更改密码,以增强密码安全性。 嗨,我的标志都在用户实体中工作,我只是无法让事件监听器重定向到密码更改页面,它只是转到主页。如果我的标志为真,我认为我需要以某种方式中断身份验证过程,以便身份验证不会进入主页。 【参考方案1】:

您不能通过收听InteractiveLoginEvent 来执行此操作。

这个event 不包括对响应对象的访问,并且返回一个来自监听器的对象不会让你无处可去,因为没有人在等待监听器返回任何东西。 p>

但您可以在 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')));

    

【讨论】:

您好,感谢您的帮助。我走得更远,但现在我在重定向发生时遇到“ERR_TOO_MANY_REDIRECTS”。不知道为什么,即使我只是重定向回登录页面? 是的,你得到了一个无限的重定向循环。我的错。我现在在手机上,当我回到家时,我会更新答案。但是你需要做的是检查用户没有尝试访问“更改密码”页面,并且不要在这种情况下执行重定向。 酷,我会尝试解决,但如果我自己无法解决,我可能需要您稍后更新解决方案。再次感谢,非常有帮助 我比我更喜欢你的方法,它看起来更整洁。再次感谢!【参考方案2】:

这是基于上述答案和帮助的最后一段代码

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

【讨论】:

以上是关于首次登录 symfony 应用程序时强制更改密码的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET Core 中首次登录时强制重定向到另一个页面

新用户首次登录时强制进行 2 因素身份验证 .NET Core

EasyNVR新增功能:播放器加载图标可配置匿名登录配置首次登录密码强制修改

Facebook 应用程序 - 用户首次登录应用程序后测试用户 ID 更改

“用户必须在下次登录时更改密码”时LDAP验证失败。有解决方案吗

如何检查用户是不是刚刚在 Firebase 中首次登录 Google