2010-09-12 88 views
1

我正在考虑实现条件许可的最佳方式,即用户和团队是m-to-m。但是每个团队也与用户表有一对一的“领导者”关系。Symfony/sfDoctrineGuard有条件许可

为了简单起见,假设我们有两个权限级别“用户”和“管理员”。然后可以说,只有某些团队管理任务,即群组电子邮件,只能由该团队的领导发送。

目前,每个针对团队领导者的操作都会查询数据库,以检查当前用户是团队领导者(记住用户可能会领导多个团队)。我个人不喜欢看到“if($ user-> isLeader($ team))”到处都是。

我已经考虑设置用户在登录用户会话(ala phpBB)时使用的团队列表,或者使用symfony过滤器来执行相同的操作。

但是,在第一种方法中,如果其他用户可能会更改团队的领导者,则数据可能会过时。第二种方法需要对每个页面加载额外的数据库查询。

有什么更好的点子? 注意:在一个项目中有多个应用程序需要共享相同的权限模型(即后端和api)

回答

0

我看到2个选项:

覆盖sfDoctrineGuardUser::getGuardUser()

覆盖的sfDoctrineGuardUser的getGuardUser方法时,得到它取小组的用户。这需要额外的左连接,但它可以节省您以后的查询。

/** 
* Overridden getGuardUser to automatically fetch Teams with User 
* @see plugins/sfDoctrineGuardPlugin/lib/user/sfGuardSecurityUser#getGuardUser() 
*/ 
public function getGuardUser() 
{ 
    if (!$this->user && $id = $this->getAttribute('user_id', null, 'sfGuardSecurityUser')) 
    { 
    $this->user = sfGuardUserTable::findUserByIdWithTeams($id); //write this query to fetch a user with his teams 

    if (!$this->user) 
    { 
     // the user does not exist anymore in the database 
     $this->signOut(); 

     throw new sfException('The user does not exist anymore in the database.'); 
    } 
    } 

    return $this->user; 
} 

然后,您可以根据通过过滤器或通过重写hasCredential他的团队添加用户的凭据。

的Invalidate缓存球队状态

如果你不希望任何其他查询,唯一的附加选项我看到的是使用全局高速缓存。这将涉及以下内容:

  • 缓存用户对登录
  • 队伍或团队基于证书当组长被删除或添加,这样做apc_add(team_invalid_[team_id], true, [length_of_session])
  • 每当添加用户的凭据(经第一个选项中描述的方法之一),请检查缓存以查看它们是否无效。
+0

这非常接近我所追求的。 我可能会使用memcache实现类似的解决方案。 – xzyfer 2010-09-14 11:29:57

0

我已经通过在myUser中覆盖hasCredential方法来实现类似的目的,凭证是必需的。

如:

public function hasCredential($credential, $useAnd = true) { 

    // make sure the symfony core always passes the team leader permission, we handle it later ourselves 
    $this->addCredential('team_leader'); 
    $ret = parent::hasCredential($credential, $useAnd); 

    // if other checks have failed, return false now, no point continuing 
    if (!$ret) return false; 

    if ($credential == 'team_leader' || (is_array($credential) && in_array('team_leader', $credential))) { 
    // do stuff here. in this example, we get the object from a route and check the user is a leader 
    $route = sfcontext::getinstance()->getRequest()->getAttribute('sf_route'); 
    if (!$route instanceof sfObjectRoute) { 
     throw new sfConfigurationException(sprintf('team_leader credential cannot be used against routes of class %s - must be sfObjectRoute', get_class($route))); 
    } 
    return $this->isLeader($route->getObject()); 
    } 
    return $ret; 
} 

然后,您可以添加 “team_leader” 凭证security.yml像使用任何其他。

显然这取决于你使用sfObjectRoutes,所以如果你不能做到这一点并且不能适应你正在使用的东西,但是我认为它是一个很好的解决方案,当你可以使用它时!

如果你担心额外的查询,你可以看看围绕isLeader调用的一些缓存。