如何在登录时使用symfony2(和fosUserBundle)动态添加用户角色


how to add user roles dynamically upon login with symfony2 (and fosUserBundle)?

在我的应用程序中,用户可以随着时间的推移在免费用户和高级用户之间切换,当他们的订阅到期时,他们不再拥有高级特权。

我想我可以偷工减料,不在数据库中存储高级用户角色,只存储他们付款的日期,这样就不需要添加cron作业,也不需要从我的用户中删除角色高级。

我想到的解决方案是在用户实体上这样做:

public function __construct()
{
    if ( $this->hasPlus() )
    {       
        $this->addRole('ROLE_PLUSUSER');
    }
}

其中hasPlus是一个比较当前日期和截止日期的函数,如果用户仍在付款,则返回true。

现在,这不起作用,所以我想也许有人可以为我阐明这一点——我知道角色是在登录时添加的,如果我在登录后添加角色,我需要注销并重新登录才能生效,但在这里,我试图在构建我的用户对象时添加角色,但它仍然不起作用。。。

根据下面的优秀答案添加了eventListener,仍然无法向用户添加角色:

<?php
namespace Hemekonomi'UserBundle'EventListener;
use Symfony'Component'Security'Http'Event'InteractiveLoginEvent;
use Symfony'Component'Security'Core'SecurityContext;
use Symfony'Component'HttpFoundation'Session;

class SecurityListener
{
    protected $security;
    protected $session;
/**
* Constructs a new instance of SecurityListener.
*
* @param SecurityContext $security The security context
* @param Session $session The session
*/
    public function __construct(SecurityContext $security, Session $session)
    {
        //You can bring whatever you need here, but for a start this should be useful to you
        $this->security = $security;
        $this->session = $session;
    }
/**
* Invoked after a successful login.
*
* @param InteractiveLoginEvent $event The event
*/
    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {
         //Your logic needs to go here
         //You can addRole 
         //Even persist if you want but bring the right tools to your constructor
         $security = $this->security; 
         if ($security->getToken()->getUser()->hasPlus()) {       
            $security->getToken()->getUser()->addRole('ROLE_PLUSUSER');    
         }
    }
}

您的逻辑不会在user实体上工作。。。

如果您想要在登录时实现,请使用Event Listeners,这就是它们如此有用的原因:-)

您需要创建一个对事件InteractiveLoginEvent做出反应的监听器,类似于以下内容:

1/创建一个监听器

<?php
namespace Acme'YourBundle'EventListener;
use Symfony'Component'Security'Http'Event'InteractiveLoginEvent;
use Symfony'Component'Security'Core'SecurityContext;
use Symfony'Component'HttpFoundation'Session'Session;

class SecurityListener
{
    protected $security;
    protected $session;
/**
* Constructs a new instance of SecurityListener.
*
* @param SecurityContext $security The security context
* @param Session $session The session
*/
    public function __construct(SecurityContext $security, Session $session)
    {
        //You can bring whatever you need here, but for a start this should be useful to you
        $this->security = $security;
        $this->session = $session;
    }
/**
* Invoked after a successful login.
*
* @param InteractiveLoginEvent $event The event
*/
    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {
         //Your logic needs to go here
         //You can addRole 
         //Even persist if you want but bring the right tools to your constructor
    }
}

请记住,InteractiveLoginEvent默认情况下已经在Symfony中创建(如您在use语句中所见),因此现在几乎没有什么可做的:

2/将此侦听器声明为服务:

services:
    acme_your_bundle.listener.login:
        class: Acme'YourBundle'EventListener'SecurityListener
        arguments: [@security.context, @session]
        tags:
            - { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }

3/如果需要,请查看文档

事件调度器组件

如何创建事件侦听器

Dustin Dobervich的登录重定向:这篇文章将给你一个很好的例子,告诉你听众是如何工作的,以及你如何在登录时简单地实现它们。