Да 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)
{
// ...
}
Я попытался таким образом, что он работает для издания (предотвращает издание для других компаний), но в списке по-прежнему отображается всем пользователи. Похоже, избиратель не вызывается для отображения строки. –
Что вы имеете в виду, отображая строку? – nifr
Поскольку мне нужно показывать только определенные пользователи в сетке списка, для них не должно отображаться строка (вместо того, чтобы появляться только для чтения). Примечание. Я говорю о сетке SonataAdmin –