2013-01-07 21 views
6

Sono un po 'sconcertato dal modo in cui gli elenchi di controllo degli accessi sono implementati in Symfony2.Come implementare ACL ruolo/risorse in Symfony2

In Zend Framework (versioni 1 & 2), un elenco di risorse e un elenco di ruoli sono definiti e ogni ruolo viene assegnato un sottoinsieme delle risorse è consentito l'accesso. Le risorse e i ruoli sono quindi il vocabolario principale dell'implementazione ACL, che non è il caso in Symfony2, dove solo la regola dei ruoli.

In un database di applicazioni legacy, ho tabelle che definiscono un elenco di ruoli, un elenco di risorse e un elenco di risorse consentite per ciascun ruolo (relazione molti-a-molti). Ad ogni utente viene assegnato un ruolo (admin, super admin, editor e così via).

Ho bisogno di fare uso di questo database in un'applicazione Symfony2. mie risorse simile a questa: ARTICLE_EDIT, ARTICLE_WRITE, COMMENT_EDIT, ecc

mio User entità in Symfony implementa l'interfaccia Symfony\Component\Security\Core\User\UserInterface e quindi ha un metodo di getRoles).

Intendo utilizzare questo metodo per definire le risorse consentite, il che significa che utilizzo i ruoli come risorse (intendo che le cosiddette risorse in Zend Framework sono chiamate ruoli qui).

Confermate che dovrei usare questo metodo?

Ciò significa che non mi interessa più il ruolo (admin, editor, ...) di ciascun utente, ma solo le sue risorse.

Vorrei quindi utilizzare $this->get('security.context')->isGranted('ROLE_ARTICLE_WRITE') nei miei controller.

È questo il modo giusto per farlo e non sarebbe un modo eluso per utilizzare i ruoli in Symfony?

risposta

2

Per rispondere a questa domanda anni più tardi, è stato abbastanza facile da risolvere.

La soluzione è combinare le nozioni di ruoli e risorse.

Supponiamo che una tabella role, una tabella resource e role_resource siano definite da molti a molti.

Gli utenti sono memorizzati in una tabella user.

Qui ci sono le corrispondenti entità Doctrine:

utente:

use Symfony\Component\Security\Core\User\UserInterface; 

class User implements UserInterface 
{ 
    /** 
    * @Id @Column(type="integer") 
    * @GeneratedValue 
    */ 
    private $id; 

    /** 
    * @ManyToOne(targetEntity="Role") 
    * @JoinColumn(name="role_id", referencedColumnName="id") 
    **/ 
    private $role; 

    // ... 
} 

Ruolo:

class Role 
{ 
    /** 
    * @Id @Column(type="integer") 
    * @GeneratedValue 
    */ 
    private $id; 

    /** @Column(type="string") */ 
    private $name; 

    /** 
    * @ManyToMany(targetEntity="Resource") 
    * @JoinTable(name="role_resource", 
    *  joinColumns={@JoinColumn(name="role_id", referencedColumnName="id")}, 
    *  inverseJoinColumns={@JoinColumn(name="resource_id", referencedColumnName="id")} 
    *  ) 
    **/ 
    private $resources; 

    // ... 
} 

risorse:

class Resource 
{ 
    /** 
    * @Id @Column(type="integer") 
    * @GeneratedValue 
    */ 
    private $id; 

    /** @Column(type="string") */ 
    private $name; 

    // ... 
} 

Quindi ora la soluzione è l'attuazione delgetRoles di UserInterface in questo modo:

use Symfony\Component\Security\Core\User\UserInterface; 
use Symfony\Component\Security\Core\Role\Role; 

class User implements UserInterface 
{ 
    // ... 

    /** 
    * @var Role[] 
    **/ 
    private $roles; 

    /** 
    * {@inheritDoc} 
    */ 
    public function getRoles() 
    { 
     if (isset($this->roles)) { 
      return $this->roles; 
     } 

     $this->roles = array(); 

     $userRole = $this->getRole(); 

     $resources = $userRole->getResources(); 

     foreach ($resources as $resource) { 
      $this->roles[] = new Role('ROLE_' . $resource); 
     } 

     return $this->roles; 
    } 

} 

In questo modo, le risorse attribuite per l'utente corrente può essere controllato in questo modo (considerando che c'è una risorsa il cui nome è ARTICLE_WRITE):

$this->get('security.context')->isGranted('ROLE_ARTICLE_WRITE')