2010-09-12 33 views
1

Je réfléchis à la meilleure façon d'implémenter les permissions conditionnelles, c'est-à-dire que les utilisateurs et les équipes sont de m-à-m. Mais chaque équipe a également une relation "Leader" 1-à-m avec la table Utilisateur. Par souci de simplicité, disons que nous avons deux niveaux d'autorisation, "Utilisateur" et "Admin". Ensuite, disons que seules certaines tâches d'administration de l'équipe, c'est-à-dire les courriels de groupe, ne peuvent être envoyées que par le chef de l'équipe.Autorisations conditionnelles Symfony/sfDoctrineGuard

À l'heure actuelle, chaque action spécifique aux chefs d'équipe interroge la base de données pour vérifier si l'utilisateur actuel est le chef d'équipe (en gardant à l'esprit qu'un utilisateur peut diriger plusieurs équipes). Personnellement, je n'aime pas voir "if ($ user-> isLeader ($ team))" partout.

J'ai envisagé de définir une liste d'équipes dirigées par un utilisateur dans la session utilisateur lors de la connexion (ala phpBB) ou en utilisant un filtre symfony pour faire de même. Cependant, dans la première approche, les données peuvent devenir périmées dans le cas où un autre utilisateur peut changer le leader d'une équipe. La deuxième approche nécessite une requête de base de données supplémentaire sur chaque chargement de page.

De meilleures idées? Note: il y a application multiple dans l'un des projets qui ont besoin de partager le même modèle d'autorisation (c.-à-backend et api)

Répondre

0

Je vois 2 options:

Remplacer sfDoctrineGuardUser::getGuardUser()

Remplacer la méthode getGuardUser de sfDoctrineGuardUser pour aller chercher les équipes quand il s'est l'utilisateur. Cela nécessite une jointure à gauche supplémentaire, mais elle vous permet d'économiser des requêtes ultérieures.

/** 
* Overridden getGuardUser to automatically fetch Teams with User 
* @see plugins/sfDoctrineGuardPlugin/lib/user/sfGuardSecurityUser#getGuardUser() 
*/ 
public function getGuardUser() 
{ 
    if (!$this->user && $id = $this->getAttribute('user_id', null, 'sfGuardSecurityUser')) 
    { 
    $this->user = sfGuardUserTable::findUserByIdWithTeams($id); //write this query to fetch a user with his teams 

    if (!$this->user) 
    { 
     // the user does not exist anymore in the database 
     $this->signOut(); 

     throw new sfException('The user does not exist anymore in the database.'); 
    } 
    } 

    return $this->user; 
} 

Vous pouvez ensuite ajouter les informations d'identification de l'utilisateur en fonction de ses équipes à travers un filtre ou par hasCredential remplaçant.

statuts équipe en cache Invalidate

Si vous ne voulez pas des questions supplémentaires, la seule option supplémentaire que je vois est d'utiliser un cache global.Cela impliquerait les éléments suivants:

  • Cache équipes ou équipe informations d'identification basées sur signe sur
  • de l'utilisateur Quand un chef d'équipe est retiré ou ajouté, faire quelque chose comme apc_add(team_invalid_[team_id], true, [length_of_session])
  • Chaque fois que sont ajoutées les informations d'identification de l'utilisateur (via l'une des méthodes décrites dans la première option), vérifiez le cache pour voir si elles sont invalides.
+0

Ceci est très proche de ce que je suis après. Je vais probablement mettre en œuvre une solution similaire en utilisant memcache. – xzyfer

0

J'ai réalisé quelque chose de similaire de plus-riding la méthode hasCredential dans myUser pour exécuter des contrôles personnalisés lorsqu'un certain un justificatif d'identité est requis.

par exemple:

public function hasCredential($credential, $useAnd = true) { 

    // make sure the symfony core always passes the team leader permission, we handle it later ourselves 
    $this->addCredential('team_leader'); 
    $ret = parent::hasCredential($credential, $useAnd); 

    // if other checks have failed, return false now, no point continuing 
    if (!$ret) return false; 

    if ($credential == 'team_leader' || (is_array($credential) && in_array('team_leader', $credential))) { 
    // do stuff here. in this example, we get the object from a route and check the user is a leader 
    $route = sfcontext::getinstance()->getRequest()->getAttribute('sf_route'); 
    if (!$route instanceof sfObjectRoute) { 
     throw new sfConfigurationException(sprintf('team_leader credential cannot be used against routes of class %s - must be sfObjectRoute', get_class($route))); 
    } 
    return $this->isLeader($route->getObject()); 
    } 
    return $ret; 
} 

Vous pouvez ensuite ajouter le "team_leader" lettres de créance à security.yml comme vous le feriez pour tout autre.

Évidemment, cela dépend de vous en utilisant sfObjectRoutes, donc peut-être pas adapté si vous ne pouvez pas faire cela et ne peut pas adapter ce que vous utilisez, mais je pense que c'est une bonne solution quand vous pouvez l'utiliser!

Si vous êtes préoccupé par des requêtes supplémentaires, vous pouvez envisager de mettre en cache un peu de mise en cache autour des appels isLeader.