为用户动态添加角色
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 中角色属性几乎毫无意义,它是事实来源的令牌以上是关于为用户动态添加角色的主要内容,如果未能解决你的问题,请参考以下文章
业务逻辑:完成认证用户的动态授权功能 完成Shiro整合Ehcache缓存权限数据
Spring Security 在运行时动态添加/删除 antMatchers 和角色