为用户动态添加角色

Posted

技术标签:

【中文标题】为用户动态添加角色【英文标题】:Dynamically adding roles to a user 【发布时间】:2012-02-11 08:20:35 【问题描述】:

我们正在使用 Symfony2 的角色功能来限制用户访问我们应用程序的某些部分。用户可以购买年度订阅,我们的每个User 实体都有许多Subscription 实体,它们都有开始日期和结束时间。

现在,有没有一种方法可以根据用户是否拥有“活动”订阅来动态地向他们添加角色?在 Rails 中,我只是让模型处理它是否具有必要的权限,但我知道根据设计 symfony2 实体不应该有权访问 Doctrine。

我知道您可以从实体实例中访问实体的关联,但这会通过所有用户的订阅对象,这对我来说似乎不必要的麻烦。

【问题讨论】:

【参考方案1】:

我认为你最好设置一个自定义选民和属性。

/**
 * @Route("/whatever/")
 * @Template
 * @Secure("SUBSCRIPTION_X")
 */
public function viewAction()

    // etc...

SUBSCRIPTION_X 角色(又名属性)需要由自定义选民类处理。

class SubscriptionVoter implements VoterInterface

    private $em;

    public function __construct($em)
    
        $this->em = $em;
    

    public function supportsAttribute($attribute)
    
        return 0 === strpos($attribute, 'SUBSCRIPTION_');
    

    public function supportsClass($class)
    
        return true;
    

    public function vote(TokenInterface $token, $object, array $attributes)
    
        // run your query and return either...
        //  * VoterInterface::ACCESS_GRANTED
        //  * VoterInterface::ACCESS_ABSTAIN
        //  * VoterInterface::ACCESS_DENIED
    

您需要配置和标记您的选民:

services:
    subscription_voter:
        class: SubscriptionVoter
        public: false
        arguments: [ @doctrine.orm.entity_manager ]
        tags:
            -  name: security.voter 

【讨论】:

@webda2l 我不明白你的问题 对不起.. 我会尽量让你更容易理解。引发查询的 Voter 类仅由用户调用一次还是在每次页面加载时调用?在最后一种情况下,为了避免重复查询,最好的方法是在投票功能中使用 session 进行管理,不是吗? 您可以添加缓存机制或根据需要进行优化。 非常感谢!我以前没有调查过也没有听说过选民。我总是发现 sf2 更有趣的功能几乎没有文档记录,而且非常基本的东西太多了。【参考方案2】:

假设您的用户实体中有正确的“订阅”关系。

你可以试试这样的:

public function getRoles()

    $todayDate = new DateTime();
    $activesSubscriptions = $this->subscriptions->filter(function($entity) use ($todayDate) 
        return (($todayDate >= $entity->dateBegin()) && ($todayDate < $entity->dateEnd()));
    );

    if (!isEmpty($activesSubscriptions)) 
        return array('ROLE_OK');
    

    return array('ROLE_KO');

可以通过以下方式更改角色:

$sc = $this->get('security.context')
$user = $sc->getToken()->getUser();
$user->setRole('ROLE_NEW');
// Assuming that "main" is your firewall name :
$token = new \Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken($user, null, 'main', $user->getRoles());
$sc->setToken($token);

但在页面更改后,会调用提供者的 refreshUser 函数,有时,就像 EntityUserProvider 的情况一样,角色会被查询覆盖。 您需要一个自定义提供程序来避免这种情况。

【讨论】:

我知道。但正如我所说,我宁愿不遍历所有订阅对象,而是让 mysql 来做“繁重的工作”,因为这必须在每个请求上发生。 (我从未测试过这个,但对我来说,不必要地为一堆物体补水似乎更慢。如果我错了,请纠正我。) 您可以使用 form_login 的 success_handler 选项来使用可以访问 Doctrine 的服务。在其中,在 onAuthenticationSuccess 函数中,您执行获取正确角色的请求。而且,由于每次页面更改都会重新加载角色,因此您使用不会刷新用户的自定义用户提供程序。 但是如果角色在会话期间发生变化,用户是否不必注销并重新登录?我不想那样。 我已经编辑了我的答案。您可以强制用户在不注销的情况下更改其角色。 +1 表示第二个代码 sn-p。被困了很长时间,想知道为什么只是在我的User 实体中添加一个角色没有通过hasRole() 检查。在 Symfony 中角色属性几乎毫无意义,它是事实来源的令牌

以上是关于为用户动态添加角色的主要内容,如果未能解决你的问题,请参考以下文章

Django 权限管理-后台根据用户权限动态生成菜单

UE4 C++为角色添加血条组件并动态变化。

业务逻辑:完成认证用户的动态授权功能 完成Shiro整合Ehcache缓存权限数据

Spring Security 在运行时动态添加/删除 antMatchers 和角色

Vue电商后台管理系统项目第6篇-商品管理的商品列表和商品添加组件实现

使用 CCSpriteFrameCache 为动画精灵添加标签