2013-12-19 10 views
8

データベーステーブルuserに直接バインドされる3つの主な役割があるとしましょう:ROLE_USER,ROLE_MODERATORおよびROLE_ADMINSymfony 2 - 「別個の」役割に基づくACLチェック許可

でも、Crewsコンポーネント(以下のUMLを参照)に使用される他の役割もあります。 Crewで実行されるアクションには、以下の役割を使用します。ROLE_CREW_BOSSROLE_CREW_LEFTHANDROLE_CREW_RIGHTHANDROLE_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を持つすべてのユーザーではなく、1つは、特定の乗組員のためのプライベートなのでcrew_idが、設定されている1。また、役割が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ダイアグラム"、ex http://asciiflow.com/ –

答えて

3

Symfonyのデフォルトロールシステムは、ユーザーにロールバインドされています。あなたのmanyToManyテーブルにロールフィールドを持つことは、この観点からは意味がありません。あなたはおそらく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

私はsymfonyの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.ymlファイルでこれを追加します。

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

さて、あなたが取得するコンストラクタを定義する必要があります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 
} 

私はそれがあなたに役立つことを祈っています!

幸運を祈る!

乾杯。

関連する問題