Sonata用户 - 自定义字段的安全性

Pie*_*NAY 5 symfony fosuserbundle sonata-admin

我使用SonataUser和FOSUser来管理我的用户并创建了一个自定义字段company来将每个用户附加到给定的公司.

现在我只需要让用户只管理连接到同一公司的用户:

user1 company1
user2 company1
user3 company2
user4 company2
Run Code Online (Sandbox Code Playgroud)

示例:user1应该只能列出/编辑user1和user2

我应该使用ACL吗?

你能指出我正确的方向或教程来为此目的定制SonataUser吗?

Nic*_*ich 10

是ACL是要走的路.创建一个实现VoterInterface的CompanyVoter,并检查用户是否在其vote()方法内的同一公司.

食谱条目" 如何实施自己的选民将IP地址列入黑名单 "作为一个很好的介绍.

将您的访问决策经理的策略改为"一致".这意味着如果只有一个选民拒绝访问(例如,CompanyVoter),则不会授予最终用户访问权限.

# app/config/security.yml
security:
    access_decision_manager:
        strategy: unanimous
Run Code Online (Sandbox Code Playgroud)

现在创建你的选民

// 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;
   }

}
Run Code Online (Sandbox Code Playgroud)

最后将选民注册为服务

# 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 }
Run Code Online (Sandbox Code Playgroud)

...现在在你的树枝模板中使用它

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

或在你的控制器......

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

或使用JMSSecurityExtraBundle ......

/**
 * @SecureParam(name="user", permissions="EDIT")
 */
public function editUser(UserInterface $user) 
{  
    // ...
}
Run Code Online (Sandbox Code Playgroud)