2013-01-07 19 views
6

Jestem nieco zirytowany tym, jak listy kontroli dostępu są zaimplementowane w Symfony2.Jak zaimplementować rolę/zasoby ACL w Symfony2

W Zend Framework (wersje 1 & 2), wykaz zasobów a lista ról są zdefiniowane i każda rola jest przypisywana podzbiór zasobów jest on dozwolony dostęp. Zasoby i role są zatem głównym słownictwem implementacji ACL, co nie ma miejsca w Symfony2, w której rządzą tylko role.

W starszej bazie danych aplikacji mam tabele definiujące listę ról, listę zasobów i listę dozwolonych zasobów dla każdej roli (relacja wiele-do-wielu). Każdy użytkownik ma przypisaną rolę (administrator, superadministrator, redaktor itd.).

Potrzebuję skorzystać z tej bazy danych w aplikacji Symfony2. Moje zasoby wyglądać następująco: ARTICLE_EDIT, ARTICLE_WRITE, COMMENT_EDIT itd

Moja User podmiot w Symfony implementuje interfejs Symfony\Component\Security\Core\User\UserInterface i dlatego ma metodę getRoles).

Zamierzam użyć tej metody do zdefiniowania dozwolonych zasobów, co oznacza, że ​​używam ról jako zasobów (mam na myśli to, że to, co nazywamy zasobami w Zend Framework, nazywa się tu rolami).

Czy potwierdzasz, że powinienem użyć tej metody?

Oznacza to, że nie obchodzi mnie już rola (administrator, redaktor, ...) każdego użytkownika, ale tylko jego zasoby.

Chciałbym wtedy użyć $this->get('security.context')->isGranted('ROLE_ARTICLE_WRITE') w moich kontrolerach.

Czy jest to właściwy sposób na zrobienie tego i czy nie byłoby to obejście ról w Symfony?

Odpowiedz

2

Aby odpowiedzieć na to pytanie lat później, to było dość łatwe do rozwiązania.

Rozwiązaniem jest połączenie pojęć ról i zasobów.

Załóżmy, że tabela role, tabela resource i role_resource wiele do wielu relacji są zdefiniowane.

Użytkownicy są zapisani w tabeli user.

Oto odpowiednie podmioty nauką

użytkownika:

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; 

    // ... 
} 

Rola:

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; 

    // ... 
} 

zasobów:

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

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

    // ... 
} 

Więc teraz rozwiązaniem jest wdrożenie getRoles z UserInterface ten sposób:

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

} 

ten sposób zasoby przypisane do bieżącego użytkownika mogą być sprawdzane w ten sposób (biorąc pod uwagę nie jest zasobem, którego nazwa jest ARTICLE_WRITE):

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