2011-10-24 3 views
26

Symfony2 ACL 시스템을 사용하여이를 달성하는 우아한 방법을 아는 사람이 있는지 궁금합니다. 다른 기준과 결합 된 Symfony2 ACL

나는 ROLE_USER에 의해 편집 할 필요가있는 Comment 엔티티 (내 도메인 개체)가 있지만 이것은 단지 게시 된 주석 5 분 이내에 허용 - 그렇지 않으면 주석 만 ROLE_ADMIN 편집 할 수 있습니다.

ROLE_USERROLE_ADMIN으로 만 편집 할 수 있도록 간단하게 각각 RoleSecurityIdentity을 만듭니다.

이제는 ROLE_USER의 시간 요소를 통합하려고 할 때 제 문제가 발생합니다. 내 첫 번째 문제는 ACL 테이블뿐 아니라 도메인 객체의 정보가 필요하다는 것입니다. 그러나 이것은 Comment이 게시 된 시간을 보유 할 수있는 사용자 정의 ObjectIdentity 클래스를 작성하여 해결할 수 있다고 생각합니다.

지금 내가 생각하는 어려운 부분

위해 나는 또한 작성시보고 알고있는 사용자 정의 PermissionGrantingStrategy을 만들어야합니다. Comment 유형을 검사 할 때로드해야하지만로드하는 방법을 모르겠습니다. 이런 종류의 일을 구성 할 수있는 일종의 공장이 있는지 아는 사람이 있습니까? 따라서 엔터티에 특정 PermissionGrantingStrategy이 연결되어 있으면 해당 엔터티가 사용됩니다. 그렇지 않으면 기본값이 사용됩니다.

ACL 문서가 약간 희박 해 보이는 것처럼 누군가가 이것을 달성하는 방법을 알고 있다면 나는이 책이 길다는 것을 알고 있습니다. 내 폴백 솔루션은 단순히 코멘트를 편집 할 수 있는지 확인하고 ACL을 전혀 신경 쓸 필요가 없는지 확인하기 위해 일종의 서비스를 만드는 것입니다.

답변

23

유권자를 사용 해본 적이 있습니까? IP 블랙리스트 유권자를 구현하는 데는 cookbook recipe이 있지만, Comments 객체에 대한 편집 확인을 처리하도록 쉽게 수정할 수 있습니다.

Symfony\Component\Security\Acl\Voter\AclVoter (온라인 here)에서 기본 AclVoter를 볼 수 있습니다. 그러나 대체 할 필요없이 훨씬 간단해질 수 있습니다. 개념의 빠른 증거로

: 다른 사람이 내 마지막 코드를 볼 수 있지만 여기에 문제있는 제안으로 유권자를 구현할 때 내가 찾은 함정이되도록

class CommentTimestampVoter implements VoterInterface 
{ 
    public function supportsAttribute($attribute) 
    { 
     return 'edit' === $attribute; 
    } 

    public function vote(TokenInterface $token, $object, array $attributes) 
    { 
     // 1. check if $token->getUser() has ROLE_ADMIN and return VoterInterface::ACCESS_GRANTED if so 
     // 2. check if $token->getUser() equals $object->getAuthor() and return VoterInterface::ACCESS_DENIED if not 
     // 3. check that $object->getCreatedAt() is within the window allowed for editing and return VoterInterface::ACCESS_GRANTED if so 
     // 4. return VoterInterface::ACCESS_DENIED 
    } 

    public function supportsClass($class) 
    { 
     return 'Acme\CommentBundle\Entity\Comment' === $class; 
    } 
} 
+0

소리가 잘 들리고 보안 컨텍스트의 isGranted (조건부로 컨트롤을 표시하여 설명을 편집 할 때도 사용할 수 있음)를 통해 액세스 할 수 있습니다. 나는 그것이 오늘 밤에 총을 맞을 것이고 그것이 작동한다면 대답을 체크 할 것이다. 그러나 당신이 승자 위에있는 것처럼 보인다 :) 고마워! – Kasheen

+0

이 솔루션을 구현 한 후 확인해 보겠습니다. 투표자를 만들 때 함정을 많이 발견하여 도움이 될만한 코드를 게시 할 예정입니다. 그렇기 때문에 내 코드가 설명서로 제공되기를 바랍니다. 나는 정확함을 보장 할 수 없다.). – Kasheen

36

내가이 솔루션을 게시하도록하겠습니다.

supportsAttribute : 당신이 SecurityContextisGranted 메서드를 호출 할 때 실제로 당신이 실제로 속성을 직접 확인해야 당신의 vote 방법 내부 그래서 VoterInterfacevote 호출을 위임하기 전에이 방법을 확인하지 않는 것으로 나타납니다 .

supportsClass은 : 위의 문제점이 대답은 VoterInterface의 투표 수의 공장을 기반으로 선택을위한 열쇠가 될 수있는이 방법처럼 보였다하지만 실제로 symfony2 설명서를 읽

supportsClass() 메소드를 유권자가 현재 사용자 토큰 클래스를 지원하는지 확인하는 데 사용됩니다.

따라서 실제로는 Voter이 토큰 유형을 지원하는지 여부와 관계가있는 것으로 보입니다. 설상가상으로 PHP 닥은 막연한 것처럼 보입니다 :

유권자가 주어진 클래스를 지원하는지 확인하십시오. 이 방법은 return falsevote에 하드 코딩 된 경우에도 여전히 를 호출 할 것입니다 - 하여간

의 주요 문제는이 방법은 모든 유권자의 vote 메소드에 호출을 위임하기 전에 SecurityContext에 의해 확인되지 않습니다 것입니다! $attributes$object 수동으로 vote 방법에서 들어오는 확인 :

그래서 기본적으로 이야기의 교훈은 것으로 나타났다.

내 코드 :

services.yml

parameters: 
    comment_voter.class: Acme\Bundle\CommentBundle\Security\Authorization\Voter\CommentVoter 

services: 
    comment_voter: 
     class: %comment_voter.class% 
     arguments: [@service_container] 
     public: false 
     tags: 
      - { name: security.voter } 

과 유권자 클래스 :

<?php 

namespace Acme\Bundle\CommentBundle\Security\Authorization\Voter; 

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

use Acme\Bundle\CommentBundle\Entity\Comment; 
use Symfony\Component\Security\Core\User\UserInterface; 

/** 
* A class to check editing privileges for Comments. 
*/ 
class CommentVoter implements VoterInterface { 

    const AUTHOR_EDIT_TIME_LIMIT = 300; 

    private $container; 

    public function __construct($container) { 
     $this->container = $container; 
    } 

    public function supportsAttribute($attribute) { 
     return $attribute === 'EDIT'; 
    } 

    public function supportsClass($class) { 
     return true; 
    } 

    /** 
    * Checks whether or not the current user can edit a comment. 
    * 
    * Users with the role ROLE_COMMENT_MODERATOR may always edit. 
    * A comment's author can only edit within 5 minutes of it being posted. 
    * 
    * {@inheritdoc} 
    */ 
    public function vote(TokenInterface $token, $object, array $attributes) { 
     if (!($object instanceof Comment)) { 
      return VoterInterface::ACCESS_ABSTAIN; 
     } 

     // Only supports 'EDIT' for now. 
     if (!$this->supportsAttribute($attributes[0])) { 
      return VoterInterface::ACCESS_ABSTAIN; 
     } 

     $user = $token->getUser(); 
     if (!($user instanceof UserInterface)) { 
      return VoterInterface::ACCESS_DENIED; 
     } 

     // Is the token a comment moderator? 
     if ($this->container->get('security.context')->isGranted('ROLE_COMMENT_MODERATOR')) { 
      return VoterInterface::ACCESS_GRANTED; 
     } 

     // Is the token the author of the post and within the edit window. 
     $originalRevision = $object->getOriginalRevision(); 
     if ($originalRevision->getAuthor()->equals($user)) { 
      if ( 
       (time() - $originalRevision->getCreationDate()->getTimestamp()) 
       <= self::AUTHOR_EDIT_TIME_LIMIT 
      ) { 
       return VoterInterface::ACCESS_GRANTED; 
      } 
     } 

     return VoterInterface::ACCESS_DENIED; 
    } 

} 

마지막 템플릿 :

{% if is_granted('EDIT', comment) %}<a href="#">Edit</a>{% endif %} 

앞으로 도움이되기를 바라며, Problematic에 큰 감사를 표합니다.

+6

_Great_ 여기에 추가. 귀하의 legwork 주셔서 감사합니다! – Problematic

+6

감사합니다. @Problematic 및 kasheen, 이것은 Symfony 요리 책 https://github.com/symfony/symfony-docs에 큰 도움이 될 것입니다.) PR을 제출해야합니다. – maxwell2022