FOSUserBundle - 首次登录后强制更改密码

时间:2014-12-03 19:04:11

标签: php symfony fosuserbundle

在使用FOSUserBundle进行用户管理的Symfony2应用程序中,用户表已通过csv文件中的导入脚本和从数据组合生成的密码填充。

我想强制用户在首次登录时更改密码。

当事件FOSUserEvents::SECURITY_IMPLICIT_LOGIN发生时,如果字段fos_user_change_password为NULL,则重定向到路由last_login

我的想法是重写类onImplicitLogin(UserEvent $event)的方法AGI\UserBundle\EventListener\LastLoginListener,但这个类没有被覆盖:

public function onImplicitLogin(UserEvent $event) {
    $user = $event->getUser ();

    if ($user->getLastLogin () === null) {
        $user->setLastLogin ( new \DateTime () );
        $this->userManager->updateUser ( $user );
        $response = new RedirectResponse ( $this->router->generate ( 'fos_user_change_password' ) );
        $this->session->getFlashBag ()->add ( 'notice', 'Please change your password' );
        $event->setResponse ( $response );
    }
}

我已经有一个包覆盖FOSUserBundle,它适用于控制器,表单等,但看起来它不是使用eventListeners的方法。

首次登录后如何强制用户更改密码?

2 个答案:

答案 0 :(得分:9)

借助@sjagr关于驱使我fos_user.security.implicit_login的{​​{1}}以及关于doing stuff right after login的外部主题的宝贵提示,我得到了一个有效的解决方案。

AGI \ UserBundle \资源\配置\ services.yml

fos_user.security.implicit_login

AGI \ UserBundle \事件监听\ LoginListener.php

login_listener:
    class: 'AGI\UserBundle\EventListener\LoginListener'
    arguments: ['@security.context', '@router', '@event_dispatcher']
    tags:
        - { name: 'kernel.event_listener', event: 'security.interactive_login', method: onSecurityInteractiveLogin }

谢谢

答案 1 :(得分:0)

如果由于某些业务规则要求用户更改密码,则可以使用内核请求EventListener:

 VM
     Child1
         Action11
         Action12
     Child2
         Action21
         Action22
     Collection
         Item1
              ElementAction
         Item2
              ElementAction
         Item3
              ElementAction
         ...

services.yaml:

<?php

namespace App\EventListener;

use App\Model\UserInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

class ChangePasswordListener
{
    private TokenStorageInterface $security;

    private RouterInterface $router;

    private array $excludedRoutes = [
        'admin_change_password',
        'admin_login',
        'admin_login_check',
        'admin_logout',
    ];

    public function __construct(
        TokenStorageInterface $security,
        RouterInterface $router
    ) {
        $this->security = $security;
        $this->router = $router;
    }

    public function onKernelRequest(RequestEvent $event): void
    {
        if (false === $event->isMasterRequest()) {
            return;
        }

        if ($event->getRequest()->isXmlHttpRequest()) {
            return;
        }

        $currentRoute = $event->getRequest()->get('_route');
        if (\in_array($currentRoute, $this->excludedRoutes, true)) {
            return;
        }

        $token = $this->security->getToken();

        if (null === $token) {
            return;
        }

        $user = $token->getUser();

        if ($user instanceof UserInterface && $user->shouldPasswordChange()) {
            $response = new RedirectResponse($this->router->generate('admin_security_profile_change_password'));
            $event->setResponse($response);
        }
    }
}

您还应该为自己的UserInterface提供方法“ shouldPasswordChange”和自定义实现。

它在Symfony 5.0和PHP 7.4上很好用,但是如果您修改此代码,它也应在较低的PHP版本上使用。