如何立即禁用对被软删除或不再启用的用户的访问?

How to immediately disable access to a user that is soft-deleted or no longer enabled?

在我的应用程序中,具有 ROLE_ADMIN 角色的用户可以手动禁用其他用户帐户,方法是将用户帐户上的 enabled 设置为 false。

使用 user checker,用户将无法在下次尝试登录时登录:

public function checkPostAuth(UserInterface $user)
{
    if (!$user->isEnabled()) {
        throw new CustomUserMessageAuthenticationException(
            'Account is not enabled.'
        );
    }
}

我的问题是,它仅在用户尝试登录时有效。如果用户当前已登录(也可能正在使用“记住我”功能),则在他们注销之前什么也不会发生。

是否有任何方法可以立即禁止用户向其不应再访问的路由发出请求,即使该用户当前已登录?

我能做的是检查是否为需要此用户访问权限的每条路线启用了帐户,如下所示:

if ($this->getUser()->isEnabled() === false) {
    throw new \Exception("Account disabled");
}

但这似乎是一个糟糕的解决方案,因为我在很多地方都需要它。

如果您在用户 class 中实施 Symfony\Component\Security\Core\User\EquatableInterfacethe User will be logged out when isEqualTo() returns false

class User implements Symfony\Component\Security\Core\User\EquatableInterface
{
    /* ... */

    public function isEqualTo(UserInterface $user)
    {
        if (!$user instanceof User) {
            return false;
        }

        if ($this->enabled !== $user->enabled) {
            // Forces the user to log in again if enabled 
            // changes from true to false or vice-versa.
            // This could be replaced by a more sophisticated comparison.
            return false;
        }

        // do a bunch of other checks, such as comparing the 
        // password hash: this will cause the user to be logged 
        // out when their password is changed.

        return true;
    }

    /* ... */
}

Relevant documentation

我听从了 Cerad 的建议,并添加了一个监听器,如下所示。但是,要获得更好的(内置)解决方案,请参阅 Pete 的回答。

namespace App\EventListener;

use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;

class RequestListener
{

    private $security; // needed to get the user
    private $router; // needed to generate the logout-url

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

    public function __invoke(RequestEvent $event) : void
    {
        $user = $this->security->getUser();

        // Don't do anything if no user is logged in.
        if ($user === null) {
            return;
        }

        if ($user->isEnabled() === false) {
            // Generate the logout url based on the path name and redirect to it.
            $url = $this->router->generate('app_logout');
            $event->setResponse(new RedirectResponse($url));
        }
    }
}