我使用 SonataUser 和 FOSUser 来管理我的用户,并创建了一个自定义字段company
来将每个用户附加到给定的公司。
现在我只需要让用户能够只管理附属于同一公司的用户:
user1 company1
user2 company1
user3 company2
user4 company2
示例:user1 应该能够仅列出/编辑 user1 和 user2
我应该使用 ACL 吗?
你能给我指出正确的方向或教程来为此目的定制 SonataUser 吗?
我使用 SonataUser 和 FOSUser 来管理我的用户,并创建了一个自定义字段company
来将每个用户附加到给定的公司。
现在我只需要让用户能够只管理附属于同一公司的用户:
user1 company1
user2 company1
user3 company2
user4 company2
示例:user1 应该能够仅列出/编辑 user1 和 user2
我应该使用 ACL 吗?
你能给我指出正确的方向或教程来为此目的定制 SonataUser 吗?
是的,ACL 是要走的路。创建一个实现 VoterInterface 的 CompanyVoter 并在其 vote() 方法中检查用户是否在同一家公司。
食谱条目“如何实现您自己的选民将 IP 地址列入黑名单”给出了很好的介绍。
将您的访问决策管理器的策略更改为“一致”。这意味着如果只有一个投票者拒绝访问(例如 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)
{
// ...
}