Symfony 2 - 基于"单独"角色的ACL检查权限

Ste*_*rem 8 acl symfony

比方说,我们有直接绑定到数据库表的3个主要角色user:ROLE_USER,ROLE_MODERATORROLE_ADMIN.

但是,我们还有一些其他角色,用于Crews组件(参见下面的UML).我用的peformed行动以下角色Crew:ROLE_CREW_BOSS,ROLE_CREW_LEFTHAND,ROLE_CREW_RIGHTHAND,ROLE_CREW_MEMBER.



      +----------------+                                     +------------------+
      | users          |                                     | crews            |
      |----------------|                                     |------------------|
      | id             |                                     | id               |
      | username       <---+                                 | name             |
      | password       |   |                             +---> cash             |
      | roles          |   |    +-------------------+    |   | ...              |
      | ...            |   |    | crew_members      |    |   |                  |
      |                |   |    |-------------------|    |   |                  |
      +----------------+   |    | crew_id +--------------+   |                  |
                           +----+ user_id           |        +--------^---------+
                                | roles             |                 |
                                | ...               |    +------------+
                                |                   |    |
                                |                   |    |   +------------------+
                                |                   |    |   | forum_topics     |
                                |                   |    |   |------------------|
                                |                   |    |   | id               |
                                +-------------------+    +---+ crew_id          |
                                                             | title            |
                                                             | description      |
                                                             | ...              |
                                                             |                  |
                                                             |                  |
                                                             |                  |
                                                             +------------------+

那是基础结构,我希望这部分是清楚的.问题来了......

问题

具有该角色的每个用户ROLE_MODERATOR都可以创建ForumTopic对象,但不能创建设置的对象crew_id,因为该对象对于特定的工作人员是私有的.此外,只有具有该角色的机组成员(也是用户)ROLE_CREW_BOSS,ROLE_CREW_LEFTHAND或者ROLE_CREW_RIGHTHAND可以编辑其机组人员的论坛主题.我如何检查这种复杂性?还有一个Voter

更新1

我已经解决了50%的问题,但它并不牢固.我已经创建了一个特定于该对象的选民Entity\\ForumTopic.

public function vote(TokenInterface $token, $object, array $attributes)
{
    if ($object instanceof ObjectIdentityInterface) {
        if ($object->getType() == 'Entity\\ForumTopic') {

            /**
             * @var Member $member
             */
            $member = $token->getUser();

            $userTable = new UserTable();
            $user = $userTable->getByMember($member);

            $userInCrewTable = new UserInCrewTable();
            $crewMember = $userInCrewTable->getByUser($user);

            if ($crewMember && in_array($crewMember->getRole(), array('boss', 'lefthand', 'righthand'))) {
                return self::ACCESS_GRANTED;
            }
        }
    }

    return self::ACCESS_ABSTAIN;
}
Run Code Online (Sandbox Code Playgroud)

这里唯一的问题是我没有使用相应的角色,所以我不能使用角色层次结构功能.任何人都有更好的解决方案或改进我目前的解决方案?

谢谢!

斯特芬

jil*_*lro 3

Symfony 的默认角色系统是角色绑定到用户。从这个角度来看,在manyToMany表crew_members中拥有角色字段是没有意义的。

您想要的是基于用户工作人员的授权,因此您应该使用 ACL 功能,并仅将角色用于全局权限。

    $objectIdentity = ObjectIdentity::fromDomainObject($forumTopic);
    $acl = $aclProvider->createAcl($objectIdentity);

    $securityIdentity = UserSecurityIdentity::fromAccount($user);

    // grant owner access
    $acl->insertObjectAce($securityIdentity, MaskBuilder::MASK_EDIT);
    $aclProvider->updateAcl($acl);
Run Code Online (Sandbox Code Playgroud)

(您可以在http://symfony.com/doc/current/cookbook/security/acl.html上查看更多文档。您还可以使用优秀的 ht​​tps: //github.com/Problematic/ProblematicAclManagerBundle

您将其与投票者结合起来:

function vote(TokenInterface $token, $object, array $attributes)
{
    if ($object instanceof ObjectIdentityInterface) {
        if ($object->getType() == 'Entity\\ForumTopic') {

            /**
             * @var Member $member
             */
            $member = $token->getUser();

            if(in_array('ROLE_MODERATOR', $member->getRoles() && empty($object->getCrew()) {
                return self::ACCESS_GRANTED;
            }

            // inject security component via dependecy injection
            // delegate further check to ACL
            if ($this->container['security']->isGranted('EDIT', $object)) {
                return self::ACCESS_GRANTED;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)