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

Posted

技术标签:

【中文标题】如何立即禁用对软删除或不再启用的用户的访问?【英文标题】:How to immediately disable access to a user that is soft-deleted or no longer enabled? 【发布时间】:2020-07-16 12:30:48 【问题描述】:

在我的应用程序中,角色为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");

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

【问题讨论】:

只需添加一个kernel request subscriber 并检查那里然后重定向到注销处理器。选民不适合这样做。 equatable 接口是一个有趣的想法,但可能无法按预期工作。 @Cerad,只是为了澄清一下,您会检查用户是否对每个请求都被禁用,如果是,他们会被重定向到注销?是否只能对需要用户访问的路由执行此操作? 是的。每个请求都是最简单的。我不知道有什么简单的方法可以区分受保护和不受保护的路线。每个请求的幕后都有很多事情发生。再添加一个侦听器不会影响性能。即使他们访问了不受保护的路线,我认为如果他们被禁用,您仍然希望将他们注销。 @Cerad 我不确定您所说的“无法按预期工作”是什么意思。我已经成功地在生产中使用 EquatableInterface 来强制用户在属性更改时注销。有我不知道的副作用吗? 如果 ($user->enabled === false) 返回 false;应该做的伎俩。当然,如果您确实想比较,那么您需要确保已启用的属性被序列化到会话中。 【参考方案1】:

如果你在你的用户类中实现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

【讨论】:

这是一个巧妙的解决方案。我将这个类与 UserInterface 一起实现,效果很好!【参考方案2】:

我按照 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));
        
    

【讨论】:

是的。和我想的差不多。尽管假设您可以修改 User 对象,但 EquatableInterface 答案将使您免于创建类。 我实际上比 EquatableInterface 更喜欢这种方法,因为它更通用

以上是关于如何立即禁用对软删除或不再启用的用户的访问?的主要内容,如果未能解决你的问题,请参考以下文章

检查是不是启用了“访问我的位置” - Android

电脑远程访问服务器关闭是啥意思?

LFCS 系列第八讲:管理用户和用户组文件权限和属性以及启用账户 sudo 访问权限

以编程方式启用定位模式高精度或省电,无需用户访问设置

启用和禁用一个组件/HTML 中的所有元素

如何以编程方式重新启用 MS Office 禁用文件列表中的文档