Documentação do Symfony2
Renderizada do repositório symfony-docs-pt-BR no Github
O componente de segurança do Symfony2 fornece várias camadas para autorizar usuários. Uma das camadas é chamada “voter”. Um voter é uma classe dedicada que verifica se o usuário possui direitos para conectar-se à aplicação ou para acessar um recurso/URL específico. Por exemplo, o Symfony2 fornece uma camada que verifica se o usuário está totalmente autorizado ou se ele tem alguns papéis esperados.
Às vezes é útil criar um voter personalizado para lidar com um caso específico não manipulado pelo framework. Nesta seção, você vai aprender como criar um voter que permitirá criar uma blacklist de usuários por seus IPs.
Um voter personalizado deve implementar Symfony\Component\Security\Core\Authorization\Voter\VoterInterface, que exige os três métodos a seguir:
interface VoterInterface
{
public function supportsAttribute($attribute);
public function supportsClass($class);
public function vote(TokenInterface $token, $object, array $attributes);
}
O método :method:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::supportsAttribute` é usado para verificar se o voter suporta o atributo de usuário fornecido (ou seja: um papel - role - como ROLE_USER, um ACL EDIT, etc.).
O método :method:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::supportsClass` é usado para verificar se o voter suporta a classe do objeto cujo acesso está sendo verificado.
O método :method:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::vote` deve implementar a lógica de negócio que verifica se o usuário tem acesso. Esse método deve retornar um dos seguintes valores:
Neste exemplo, você vai verificar se o endereço IP do usuário corresponde a uma lista de endereços na blacklist e “algo” será a aplicação. Se o IP do usuário está na lista negra, você vai retornar VoterInterface::ACCESS_DENIED, caso contrário você vai retornar VoterInterface::ACCESS_ABSTAIN pois o propósito desse voter é somente negar acesso, e não conceder.
Para adicionar um usuário na lista negra com base em seu endereço IP, você pode usar o serviço request e comparar o endereço IP a um conjunto de endereços IP na lista negra:
// src/Acme/DemoBundle/Security/Authorization/Voter/ClientIpVoter.php
namespace Acme\DemoBundle\Security\Authorization\Voter;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class ClientIpVoter implements VoterInterface
{
protected $requestStack;
private $blacklistedIp;
public function __construct(RequestStack $requestStack, array $blacklistedIp = array())
{
$this->requestStack = $requestStack;
$this->blacklistedIp = $blacklistedIp;
}
public function supportsAttribute($attribute)
{
// you won't check against a user attribute, so return true
return true;
}
public function supportsClass($class)
{
// your voter supports all type of token classes, so return true
return true;
}
public function vote(TokenInterface $token, $object, array $attributes)
{
$request = $this->requestStack->getCurrentRequest();
if (in_array($request->getClientIp(), $this->blacklistedIp)) {
return VoterInterface::ACCESS_DENIED;
}
return VoterInterface::ACCESS_ABSTAIN;
}
}
É isso! O voter está pronto. O próximo passo é injetar o voter na camada de segurança. Isso pode ser feito facilmente através do container de serviço.
Tip
A sua implementação dos métodos :method:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::supportsAttribute` e :method:`Symfony\\Component\\Security\\Core\\Authorization\\Voter\\VoterInterface::supportsClass` não está sendo chamada internamente pelo framework. Depois de ter registado o seu voter o método vote() sempre será chamado, independentemente desses dois métodos retornarem true ou não. Portanto, você precisa chamar os métodos na sua implementação do método vote() e retornar ACCESS_ABSTAIN se o seu voter não suporta a classe ou atributo.
Para injetar o voter na camada de segurança, você deve declará-lo como um serviço, e adicionar a tag security.voter:
Tip
Certifique-se de importar esse arquivo de configuração em seu arquivo de configuração principal da aplicação (por exemplo, app/config/config.yml). Para mais informações veja Importando configuração com imports. Para ler mais sobre a definição de serviços em geral, consulte o capítulo Container de Serviço .
Para que o novo voter tenha efeito, é necessário alterar a estratégia de decisão de acesso padrão, que, concede acesso se qualquer voter conceder acesso.
Neste caso, escolha a estratégia unanimous. Ao contrário da estratégia affirmative (o padrão), com a estratégia unanimous, se apenas um voter negar o acesso (por exemplo, o ClientIpVoter), o acesso não é concedido ao o usuário final.
Para fazer isso, sobrescreva a seção access_decision_manager padrão de seu arquivo de configuração da aplicação com o seguinte código.
É isso! Agora, no momento de decidir se um usuário deve ou não ter acesso, o novo voter vai negar acesso a qualquer usuário na lista negra de IPs.
See also
Para um uso mais avançado ver components-security-access-decision-manager.