2012-01-16 17 views
14

Estamos utilizando la función de funciones de Symfony2 para restringir el acceso de los usuarios a ciertas partes de nuestra aplicación. Cada una de nuestras entidades de Usuario tiene muchas entidades de Suscripción que tienen una fecha de inicio y un final y los usuarios pueden comprar suscripciones anuales.Añadiendo roles dinámicamente a un usuario

Ahora, ¿hay alguna manera de agregar dinámicamente un rol a un usuario en función de si tienen una suscripción 'activa'? En los rails, simplemente dejaría que el modelo maneje si tiene los derechos necesarios, pero sé que, por diseño, las entidades de Symfony2 no deberían tener acceso a Doctrine.

sé que se puede acceder a las asociaciones de la entidad desde el interior de una instancia de entidad, pero que pasaría por todos objetos de suscripción del usuario y que parece unnecessaryly engorroso para mí.

Respuesta

27

Creo que sería mejor configurar un votante personalizado y un atributo. tendría que ser manejado por una clase de votantes a medida

/** 
* @Route("/whatever/") 
* @Template 
* @Secure("SUBSCRIPTION_X") 
*/ 
public function viewAction() 
{ 
    // etc... 
} 

El SUBSCRIPTION_X papel (también conocido como atributo).

class SubscriptionVoter implements VoterInterface 
{ 
    private $em; 

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

    public function supportsAttribute($attribute) 
    { 
     return 0 === strpos($attribute, 'SUBSCRIPTION_'); 
    } 

    public function supportsClass($class) 
    { 
     return true; 
    } 

    public function vote(TokenInterface $token, $object, array $attributes) 
    { 
     // run your query and return either... 
     // * VoterInterface::ACCESS_GRANTED 
     // * VoterInterface::ACCESS_ABSTAIN 
     // * VoterInterface::ACCESS_DENIED 
    } 
} 

Usted tendría que configurar y etiquetar su votante:

services: 
    subscription_voter: 
     class: SubscriptionVoter 
     public: false 
     arguments: [ @doctrine.orm.entity_manager ] 
     tags: 
      - { name: security.voter } 
+0

@ webda2l No entiendo tu pregunta –

+0

Lo siento ... Trataré de ser un poco más fácil de entender. La clase de votante, que induce una consulta, solo se llama una vez por el usuario o en cada carga de página? En este último caso, para evitar la repetición de la consulta, la mejor manera será gestionar la sesión en la función de votación, ¿no es así? – webda2l

+0

Puede agregar un mecanismo de almacenamiento en caché u optimizarlo como lo considere conveniente. –

2

Suponiendo que tiene la relación correcta de "suscripciones" en su entidad de usuario.

Puede tal vez intente algo como:

public function getRoles() 
{ 
    $todayDate = new DateTime(); 
    $activesSubscriptions = $this->subscriptions->filter(function($entity) use ($todayDate) { 
     return (($todayDate >= $entity->dateBegin()) && ($todayDate < $entity->dateEnd())); 
    }); 

    if (!isEmpty($activesSubscriptions)) { 
     return array('ROLE_OK'); 
    } 

    return array('ROLE_KO'); 
} 

Cambio de papel se puede hacer con:

$sc = $this->get('security.context') 
$user = $sc->getToken()->getUser(); 
$user->setRole('ROLE_NEW'); 
// Assuming that "main" is your firewall name : 
$token = new \Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken($user, null, 'main', $user->getRoles()); 
$sc->setToken($token); 

Pero después de un cambio de página, la función refreshUser del proveedor se llama y, a veces, como este es el caso con EntityUserProvider, el rol es sobreescrito por una consulta. Necesita un proveedor personalizado para evitar esto.

+0

lo sé. Pero como dije, prefiero no examinar todos los objetos de la suscripción, pero dejar que MySQL realice el "trabajo pesado", ya que esto tiene que suceder en cada solicitud. (Nunca probé esto, pero me parece más lento hidratar innecesariamente un montón de objetos. Corrígeme si me equivoco). – maiwald

+0

Puede usar la opción success_handler de form_login, para usar un servicio con acceso a Doctrine. Dentro de él, en la función OnAuthenticationSuccess, realiza la solicitud para obtener el rol correcto. Y, como los roles se vuelven a cargar con cada cambio de página, utiliza un proveedor de usuario personalizado que no actualiza al usuario. – webda2l

+0

¿Pero un usuario no tendría que cerrar la sesión y volver a ingresar de nuevo si los roles cambian durante una sesión? No quisiera eso. – maiwald

Cuestiones relacionadas