2013-12-19 3 views
8

user : ROLE_USER, ROLE_MODERATORROLE_ADMIN에 직접 바인딩되는 3 가지 주요 역할이 있다고 가정 해 봅니다.Symfony 2 - '별도의'역할에 기반한 ACL 검사 권한

그러나 여기에는 Crews 구성 요소 (아래 UML 참조)에 사용되는 다른 역할이 있습니다. 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  | 
                  | ...    | 
                  |     | 
                  |     | 
                  |     | 
                  +------------------+

그 기본 구조입니다. 그 부분이 분명하길 바랍니다. 이제 문제가 온다 ...

문제

ForumTopic 개체를 만들 수 있습니다 역할 ROLE_MODERATOR을 가진 모든 사용자,하지만 그 중 하나가 특정 승무원 개인이기 때문에 crew_id가 설정되어 하나. 또한 역할이 ROLE_CREW_BOSS, ROLE_CREW_LEFTHAND 또는 ROLE_CREW_RIGHTHAND 인 승무원 (사용자도 있음) 만 승무원의 포럼 주제를 편집 할 수 있습니다. 이러한 종류의 복잡성을 어떻게 확인합니까? 아마 Voter로?

UPDATE 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; 
} 

여기에 유일한 문제는 각각의 역할을 사용하지 않는, 그래서 예를 들어 역할 계층 기능을 사용할 수 없다는 것입니다. 누구나 현재 솔루션에서 더 나은 솔루션이나 개선점을 얻었습니까?

감사합니다.

스테

+5

+1 –

+0

저에게 말해주세요, 그런 realtion-diagramms을 만드는 도구가 있습니다 :) –

+0

@ V-Light 이제 내가 사용했지만, "google"ASCII diagram "ex http://asciiflow.com/ –

답변

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); 

(당신은 http://symfony.com/doc/current/cookbook/security/acl.html에 대한 자세한 문서를 확인하실 수 있습니다 또한 우수한 https://github.com/Problematic/ProblematicAclManagerBundle 사용할 수 있습니다.)

당신은 유권자와 결합 : 데이터베이스 다이어그램 XD에 대한

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; 
      } 
     } 
    } 
+0

이것은 올바른 방향으로 나를 싣습니다 :) 감사합니다! –

0

나는 심포니의 ACL을 사용합니다 :

// creating the ACL 
$aclProvider = $this->get('security.acl.provider'); 
$objectIdentity = ObjectIdentity::fromDomainObject($comment); 
$acl = $aclProvider->createAcl($objectIdentity); 

$roleSecurityIdentity = new RoleSecurityIdentity('ROLE_CREW'); 
$securityIdentity = $roleSecurityIdentity; 

// grant owner access 
$acl->insertObjectAce($securityIdentity, MaskBuilder::MASK_OWNER); 
$aclProvider->updateAcl($acl); 
0

당신은 해결책을 만질 수! 역할을 확인하려면 몇 가지 작업 만 수행하면됩니다. 얻을 수있는 생성자를 정의하는, 당신이해야합니다

services: 
    your_app.security.voter.forum_topic_owner: 
     class: Your\AppBundle\Security\Authorization\Voter\ForumTopicOwnerVoter 
     arguments: ["@security.context"] 
     tags: 
      - { name: security.vote 

을 지금 :

이 services.yml 파일이 추가 : 첫째, 보안 컨텍스트를 구성하기 위해 서비스로 귀하의 유권자 등록 SecurityContext에와 투표 방법에서 사용하기 : 이제

<?php 

namespace Your\AppBundle\Security\Authorization\Voter; 

use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; 
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; 
use Symfony\Component\Security\Core\SecurityContext; 

class ForumTopicOwnerVoter implements VoterInterface 
{ 
    /** @var SecurityContext */ 
    protected $securityContext; 

    /** 
    * @param SecurityContext  $securityContext SecurityContext is the main entry point of the Security component. 

    */ 
    public function __construct(SecurityContext $securityContext) 
    { 
     $this->securityContext = $securityContext; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    public function supportsAttribute($attribute) 
    { 
     return 'FORUM_TOPIC_OWNER' === $attribute; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    public function supportsClass($class) 
    { 
     return $class->getType() == 'Entity\\ForumTopic'; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    public function vote(TokenInterface $token, $forumTopic, array $attributes) 
    { 
     foreach ($attributes as $attribute) { 
      if ($this->supportsAttribute($attribute) && $this->supportsClass($forumTopic)) { 
       $user = $token->getUser(); 
       if ($user->hasRole('ROLE_CREW_BOSS') 
        or $this->securityContext->isGranted('ROLE_LEFTHAND') 
        ) { 
         return VoterInterface::ACCESS_GRANTED; 
       } 
      } 
     } 

     return VoterInterface::ACCESS_DENIED; 
    } 
} 

, 당신은 할 수있다, 분명히 당신은이 작업을 수행하는 방법을 알고 그것은 당신의 문제가 아니었다, 당신이 ForumTopic 객체에 전화를해야하는 유권자가 어쨌든 당신 주위에 둘러 볼 것을 제안합니다. 잘 알려진 Jms/SecurityExtraBundle의 cureParam 주석. 내가 당신에게 도움이 되었기를 바랍니다

namespace Your\AppBundle\Controller; 

use Symfony\Bundle\FrameworkBundle\Controller\Controller; 
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; 
use JMS\SecurityExtraBundle\Annotation\Secure; 
use JMS\SecurityExtraBundle\Annotation\SecureParam; 

/** 
* ForumTopic controller. 
* 
*/ 
class ForumTopicController extends Controller 

/** 
* Edit an existing forum topic entity. 
* 
* @param Request $request An HTTP request. 
* @param ForumTopic $forumTopic A forumTopic entity. 
* 
* @Secure(roles="ROLE_CREW") 
* @SecureParam(name="forumTopic", permissions="FORUM_TOPIC_OWNER") 
* @ParamConverter("forumTopic", class="YourAppBundle:ForumTopic") 
*/ 
public function editAction(Request $request, ForumTopic $forumTopic) 
{ 
    //Add here your logic 
} 

: 여기에 귀하의 컨트롤러 액션에서 사용할 수있는 방법입니다!

행운을 빕니다!

건배.