簡體   English   中英

FOSUserBundle - 首次登錄后強制更改密碼

[英]FOSUserBundle - Force password change after first login

在使用 FOSUserBundle 進行用戶管理的 Symfony2 應用程序中,用戶表已通過從 csv 文件的導入腳本和從數據組合生成的密碼進行填充。

我想強制用戶在第一次登錄時更改他的密碼。

當事件FOSUserEvents::SECURITY_IMPLICIT_LOGIN發生時,如果字段last_login為 NULL,則重定向到路由fos_user_change_password

我的想法是像這樣重寫AGI\\UserBundle\\EventListener\\LastLoginListener類的onImplicitLogin(UserEvent $event) ,但該類沒有被覆蓋:

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 的方法。

如何強制用戶在第一次登錄后更改密碼?

在@sjagr 關於fos_user.security.implicit_login的寶貴提示的幫助下,我找到了fos_user.security.implicit_login和一個關於登錄后立即做事的外部主題,我得到了一個fos_user.security.implicit_login解決方案。

AGI\\UserBundle\\Resources\\config\\services.yml

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

AGI\\UserBundle\\EventListener\\LoginListener.php

<?php

namespace AGI\UserBundle\EventListener;

use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class LoginListener {

    private $securityContext;
    private $router;
    private $dispatcher;

    public function __construct(SecurityContext $securityContext, Router $router, EventDispatcherInterface $dispatcher) {
        $this->securityContext = $securityContext;
        $this->router = $router;
        $this->dispatcher = $dispatcher;
    }
    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event) {
        if ($this->securityContext->isGranted ( 'IS_AUTHENTICATED_FULLY' )) {
            $user = $event->getAuthenticationToken ()->getUser ();

            if ($user->getLastLogin () === null) {
                $this->dispatcher->addListener ( KernelEvents::RESPONSE, array (
                        $this,
                        'onKernelResponse' 
                ) );
            }
        }
    }
    public function onKernelResponse(FilterResponseEvent $event) {
        $response = new RedirectResponse ( $this->router->generate ( 'fos_user_change_password' ) );
        $event->setResponse ( $response );
    }
}

謝謝

如果由於某些業務規則需要用戶更改密碼,可以使用內核請求 EventListener:

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

服務.yaml:

services:
    App\EventListener\ChangePasswordListener:
        arguments:
            - '@security.token_storage'
            - '@router'
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: -100 }

您還應該提供自己的 UserInterface 方法“shouldPasswordChange”和它的自定義實現。

它適用於 Symfony 5.0 和 PHP 7.4,但如果您修改此代碼,它也適用於較低的 PHP 版本。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM