2013-06-10 2 views
5

Я использовал SonataUser с FOSUser для управления моими пользователями и создал настраиваемое поле company для присоединения каждого к данной компании.Sonata User - Безопасность в настраиваемом поле

Теперь я просто нужно, чтобы дать пользователям возможность управлять только пользователи, подключенные к одной и той же компании:

user1 company1 
user2 company1 
user3 company2 
user4 company2 

Пример: user1 должен быть в состоянии перечислить/редактировать только user1 user2 &

Должен ли я использовать списки управления доступом?

Можете ли вы указать мне правильное направление или учебник для настройки SonataUser для этой цели?

ответ

10

Да ACL - это путь. создайте CompanyVoter, реализующий VoterInterface, и проверьте, находится ли пользователь в одной компании внутри его метода голосования().

Вводная книга "How to implement your own Voter to blacklist IP Addresses" дает хорошее представление.

изменить стратегию вашего менеджера решения-решения на «единодушное». Это означает, что если только один избиратель отказывает в доступе (например, CompanyVoter), доступ не предоставляется конечному пользователю.

# app/config/security.yml 
security: 
    access_decision_manager: 
     strategy: unanimous 

Теперь создайте ваш избиратель

// src/Acme/AcmeBundle/YourBundle/Security/Authorization/Voter/CompanyVoter.php 
namespace Acme\YourBundle\Security\Authorization\Voter; 

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

use Acme\YourUserBundleBundle\Entity\User; 
use Symfony\Component\Security\Core\User\UserInterface; 

class CompanyVoter implements VoterInterface 
{ 

    private $container; 

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

    public function supportsAttribute($attribute) 
    { 
     return in_array($attribute, array(
      'EDIT', 
      'ACTIVATE', 
      // ... 
     )); 
    } 

    public function supportsClass($class) 
    { 
     return in_array("FOS\UserBundle\Model\UserInterface", class_implements($class)); 
    } 

    public function vote(TokenInterface $token, $object, array $attributes) 
    { 
     if (!($this->supportsClass(get_class($object)))) { 
      return VoterInterface::ACCESS_ABSTAIN; 
     } 

     foreach ($attributes as $attribute) { 
      if (!$this->supportsAttribute($attribute)) { 
       return VoterInterface::ACCESS_ABSTAIN; 
      } 
     } 

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

     // check if the user has the same company 
     if ($user->getCompany() == $object->getCompany()) { 
      return VoterInterface::ACCESS_GRANTED; 
     } 

     return VoterInterface::ACCESS_DENIED; 
    } 

} 

Наконец зарегистрировать избирателя в качестве службы

# src/Acme/AcmeBundle/Resources/config/services.yml 
services: 
    security.access.company_voter: 
     class:  Acme\YourBundle\Security\Authorization\Voter\CompanyVoter 
     public:  false 
     tags: 
      - { name: security.voter } 

... теперь использовать его в шаблоне веточку

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

или в вашем контроллере ...

public function editAction(UserInterface $user) 
{ 
    if ($this->get('security.context')->isGranted('EDIT',$user)) { 
     throw new \Symfony\ComponentSecurity\Core\Exception\AccessDeniedException(); 
    } 
} 

или с использованием JMSSecurityExtraBundle ...

/** 
* @SecureParam(name="user", permissions="EDIT") 
*/ 
public function editUser(UserInterface $user) 
{ 
    // ... 
} 
+0

Я попытался таким образом, что он работает для издания (предотвращает издание для других компаний), но в списке по-прежнему отображается всем пользователи. Похоже, избиратель не вызывается для отображения строки. –

+0

Что вы имеете в виду, отображая строку? – nifr

+0

Поскольку мне нужно показывать только определенные пользователи в сетке списка, для них не должно отображаться строка (вместо того, чтобы появляться только для чтения). Примечание. Я говорю о сетке SonataAdmin –

1

Как мне не нужно списки ACL здесь (только избиратели) я использовал обработчик роли безопасности сонаты.

Но у меня были проблемы с его использованием, поскольку его реализация по умолчанию isGranted() не передает текущий объект избирателю.

Поэтому я должен был продлить его, проверить мой монолог в этом github issue для более подробной информации.


Кстати, мой PR был принят по этому вопросу

Смежные вопросы