Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Kohana - ACL czyli kontrola uprawnień
phpion
post
Post #1





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Witam,
napisałem sobie prościutki moduł do obsługi uprawnień i chciałbym się nim z Wami podzielić. Poniżej przedstawiam wszystkie wymagane pliki oraz przykład użycia z wykorzystaniem kontroli dostępu do akcji kontrolera. Równie dobrze moduł może zostać wykorzystany do kontroli dostępu do innych zasobów.

application/modules/authorization/libraries/Authorization.php
  1. <?php
  2. /**
  3.  * Klasa realizująca obsługę uprawnień w systemie.
  4.  *
  5.  * @package authorization
  6.  */
  7. class Authorization {
  8.    /**
  9.      * Instancja klasy Authorization.
  10.      *
  11.      * @var Authorization
  12.      */
  13.    private static $instance = null;
  14.    
  15.    /**
  16.      * Nazwa roli aktualnego użytkownika.
  17.      *
  18.      * @var string
  19.      */
  20.    private $role;
  21.    
  22.    /**
  23.      * Tablica uprawnień.
  24.      *
  25.      * @var array
  26.      */
  27.    private $credentials = array();
  28.    
  29.    /**
  30.      * Domyślna wartość uprawnień.
  31.      *
  32.      * @var boolean
  33.      */
  34.    private $default;
  35.    
  36.    /**
  37.      * Zwraca instancję klasy Authorization
  38.      *
  39.      * @return Authorization
  40.      */
  41.    public static function instance() {
  42.        if (is_null(self::$instance)) {
  43.            self::$instance = new Authorization();
  44.        }
  45.        
  46.        return self::$instance;
  47.    }
  48.    
  49.    /**
  50.      * Wczytuje konfigurację uprawnień z pliku zewnętrznego.
  51.      *
  52.      * Dodatkowo ustawia domyślną wartość o ile została ustalona w pliku konfiguracyjnym.
  53.      */
  54.    public function loadConfig() {
  55.        $this->credentials = (array)Kohana::config('authorization.'.$this->role);
  56.        
  57.        if (isset($this->credentials[self::DEFAULT_KEY])) {
  58.            $this->default = (bool)$this->credentials[self::DEFAULT_KEY];
  59.            unset($this->credentials[self::DEFAULT_KEY]);
  60.        }
  61.        else {
  62.            $this->default = self::DEFAULT_VALUE;
  63.        }
  64.    }
  65.    
  66.    /**
  67.      * Dodaje uprawnienia do danego zasobu.
  68.      *
  69.      * @param string $resource Nazwa zasobu.
  70.      */
  71.    public function allow($resource) {
  72.        $this->credentials[$resource] = true;
  73.    }
  74.    
  75.    /**
  76.      * Odbiera uprawnienia do danego zasobu.
  77.      *
  78.      * @param string $resource Nazwa zasobu.
  79.      */
  80.    public function deny($resource) {
  81.        $this->credentials[$resource] = false;
  82.    }
  83.    
  84.    /**
  85.      * Sprawdza, czy użytkownik ma prawo dostępu do danego zasobu.
  86.      *
  87.      * W przypadku podania drugiego parametru ($method) zasób traktowany jest jako żądanie akcji kontrolera.
  88.      *
  89.      * Sprawdzanie odbywa się w kilku etapach:
  90.      * - przypisanie wartości domyślnej,
  91.      * - sprawdzenie globalnego ustawienia dla kontrolera (w przypadku akcji),
  92.      * - sprawdzenie konkretnego zasobu.
  93.      *
  94.      * Zwracana wartość jest nadpisywana nową wartością w kolejnych etapach sprawdzania.
  95.      *
  96.      * @param string $resource Nazwa zasobu.
  97.      * @param string $method Opcjonalna nazwa akcji kontrolera.
  98.      * @return boolean
  99.      */
  100.    public function isAllowed($resource, $method = null) {
  101.        $return = $this->default;
  102.        
  103.        if (!is_null($method)) {
  104.            if (isset($this->credentials[$resource.self::SEPARATOR.self::DEFAULT_KEY])) {
  105.                $return = (bool)$this->credentials[$resource.self::SEPARATOR.self::DEFAULT_KEY];
  106.            }
  107.            
  108.            $resource .= self::SEPARATOR.$method;
  109.        }
  110.        
  111.        if (isset($this->credentials[$resource])) {
  112.            $return = (bool)$this->credentials[$resource];
  113.        }
  114.        
  115.        return $return;
  116.    }
  117.    
  118.    public function setRole($v) {
  119.        $this->role = $v;
  120.    }
  121.    
  122.    public function getRole() {
  123.        return $this->role;
  124.    }
  125.    
  126.    public function setCredentials(array $v = array()) {
  127.        $this->credentials = $v;
  128.    }
  129.    
  130.    public function getCredentials() {
  131.        return $this->credentials;
  132.    }
  133.    
  134.    /**
  135.      * Wartość domyślna dla uprawnień.
  136.      *
  137.      * @var boolean
  138.      */
  139.    const DEFAULT_VALUE = false;
  140.    
  141.    /**
  142.      * Klucz oznaczający elementy domyślne.
  143.      *
  144.      * @var string
  145.      */
  146.    const DEFAULT_KEY = '*';
  147.    
  148.    /**
  149.      * Separator kontrolera oraz akcji.
  150.      *
  151.      * @var string
  152.      */
  153.    const SEPARATOR = '/';
  154. }
  155. ?>


application/modules/authorization/hooks/authorization_hook.php
  1. <?php
  2. /**
  3.  * Hook realizujący zabezpieczenie autoryzacji dostępu.
  4.  *
  5.  * @package authorization
  6.  */
  7. class Authorization_Hook {
  8.    /**
  9.      * Sprawdza czy dany użytkownik ma prawo dostępu do danej akcji kontrolera.
  10.      *
  11.      * W przypadku braku uprawnień wyświetla stronę z odpowiednim komunikatem.
  12.      *
  13.      */
  14.    public function check() {
  15.        $acl = Authorization::instance();
  16.        $acl->setRole('user'); // docelowo pobierane z sesji
  17.        $acl->loadConfig();
  18.        
  19.        if (!$acl->isAllowed(Router::$controller, Router::$method)) {
  20.            Event::add('system.401', array('Authorization_Hook', 'error'));
  21.            Event::run('system.401');
  22.        }
  23.    }
  24.    
  25.    /**
  26.      * Przekierowuje żądanie do strony z błędem braku dostępu.
  27.      *
  28.      */
  29.    public function error() {
  30.        Router::$controller = 'authorization'; 
  31.        Router::$method = 'error_401'; 
  32.        Router::$arguments  = array();
  33.    }
  34. }
  35.  
  36. Event::add('system.routing', array('Authorization_Hook', 'check'));
  37. ?>


application/modules/authorization/controllers/authorization.php
  1. <?php
  2. /**
  3.  * @package authorization
  4.  */
  5. class Authorization_Controller extends Main_Controller_Core {
  6.    public function error_401() {
  7.        $this->template->content = new View('authorization/error_401');
  8.    }
  9. }
  10. ?>

W tym momencie warto zauwazyć, iż kontroler rozszerza moją klasę Main_Controller_Core, która natomiast rozszerza Template_Core.

application/modules/authorization/views/authorization/error_401.php
  1. <?php
  2. <h3>Brak uprawnień!</h3>
  3. ?>


Całą konfigurację należy zawrzeć w konfigu dla aplikacji tj. application/config/authorization.php
  1. <?php
  2. $config = array();
  3.  
  4. $config['user'] = array(
  5.    '*' => false,
  6.    'authentication/*' => true,
  7.    'authentication/logout' => false
  8. );
  9.  
  10. $config['admin'] = array(
  11.    '*' => true
  12. );
  13. ?>

Powyższy kod definiuje 2 typy użytkowników: administratora oraz użytkownika zwykłego. Administrator ma wszelkie uprawnienia ('*' => true), natomiast w przypadku użytkownika sprawa wygląda inaczej. Początkowo odbierane są mu wszystkie uprawnienia. Następnie nadawane są uprawnienia dla wszystkich akcji kontrolera "authentication", po czym odbierana jest mu możliwość wykonania akcji "logout". W efekcie użytkownik będzie mógł się jedynie zalogować smile.gif Operacja wylogowania (oraz wszelkie pozostałe) zostały zablokowane.

Poza powyższymi krokami należy również aktywować hooki oraz dodać moduł autoryzacji w konfigu aplikacji.

Od razu uprzedzam, że skrypt nie obsługuje dziedziczenia uprawnień. Można to jednak osiągnąć np. poprzez array_merge() podczas definiowania uprawnień.

Zademonstrowałem wykorzystanie klasy na przykładzie kontroli dostępu do akcji. Jednak równie dobrze można ją wykorzystać do kontroli wewnątrz samych akcji. Przykładowo:
application/config/authorization.php
  1. <?php
  2. $config = array();
  3.  
  4. $config['user'] = array(
  5.    '*' => true,
  6.    'cos' => false
  7. );
  8. ?>

application/controllers/jakiskontroler.php
  1. <?php
  2. public function index() {
  3.    if (Authorization::instance()->isAllowed('cos')) {
  4.        // dodatkowy kod
  5.    }
  6. }
  7. ?>


Zaletą korzystania z instance() jest to, że zwraca ona główny obiekt Authorization. Główny czyli ten dotyczący aktualnie zalogowanego użytkownika. Można jednak, o czym pisałem wcześniej, na bieżąco tworzyć obiekty autoryzacyjne:

application/controllers/jakiskontroler.php
  1. <?php
  2. public function index() {
  3.    // utworzenie nowego obiektu
  4.    $acl = new Authorization();
  5.    // przypisanie roli
  6.    $acl->setRole('mietek');
  7.    // zezwolenie na dostęp do zasobu "lalala"
  8.    $acl->allow('lalala');
  9.  
  10.    if ($acl->isAllowed('lalala')) {
  11.        echo 'lalala tak';
  12.    }
  13.    else {
  14.        echo 'lalala nie';
  15.    }
  16.  
  17.    // odebranie dostępu do zasobu "lalala"
  18.    $acl->deny('lalala');
  19.  
  20.    if ($acl->isAllowed('lalala')) {
  21.        echo 'lalala tak';
  22.    }
  23.    else {
  24.        echo 'lalala nie';
  25.    }
  26. }
  27. ?>


Proszę o opinie.

pion

Ten post edytował phpion 1.12.2008, 17:12:07
Go to the top of the page
+Quote Post
bim2
post
Post #2





Grupa: Zarejestrowani
Postów: 1 873
Pomógł: 152
Dołączył: 9.04.2006
Skąd: Berlin

Ostrzeżenie: (0%)
-----


moim zdaniem troche źle to jest rozwiązane. Nie znam kohany, ale ja sprawdzałbym uprawnienia na poziomie wczytywania akcji (kontrolera). Jeśli nie ma uprawnień przekierowujesz ruch do akcji (kontrolera) Error_403 smile.gif Nie trzeba wtedy co chwilę wpisywac ifki. :]


--------------------
Go to the top of the page
+Quote Post
phpion
post
Post #3





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Cytat(bim2 @ 1.12.2008, 19:05:46 ) *
moim zdaniem troche źle to jest rozwiązane. Nie znam kohany, ale ja sprawdzałbym uprawnienia na poziomie wczytywania akcji (kontrolera). Jeśli nie ma uprawnień przekierowujesz ruch do akcji (kontrolera) Error_403 smile.gif Nie trzeba wtedy co chwilę wpisywac ifki. :]

Hmmm, no przecież jest to zautomatyzowane poprzez użycie hook'a.
  1. <?php
  2. Event::add('system.routing', array('Authorization_Hook', 'check'));
  3. ?>
Go to the top of the page
+Quote Post
kbsucha
post
Post #4





Grupa: Zarejestrowani
Postów: 113
Pomógł: 19
Dołączył: 2.08.2007

Ostrzeżenie: (0%)
-----


Bardzo fajna i w miare prosta do zastosowania biblioteka, wlasnie nie dawno pisałem podobny modul. Dla mnie np brakowałoby rozdzielenia rodzaju dostępu, chodzi mi o: read, write, del.
Fajnie, że tak szczegółowo to opisales. Może zyskasz kilku zwolenników Kohany biggrin.gif

pozdr

EDIT: Istotnie mozna i tak.

Ten post edytował kbsucha 1.12.2008, 17:43:27


--------------------
Go to the top of the page
+Quote Post
phpion
post
Post #5





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Cytat(kbsucha @ 1.12.2008, 19:11:21 ) *
Bardzo fajna i w miare prosta do zastosowania biblioteka, wlasnie nie dawno pisałem podobny modul. Dla mnie np brakowałoby rozdzielenia rodzaju dostępu, chodzi mi o: read, write, del.
Fajnie, że tak szczegółowo to opisales. Może zyskasz kilku zwolenników Kohany biggrin.gif

pozdr

Dzięki za przychylną opinię. Nie do końca rozumiem o co Ci chodzi z tym "rozdzieleniem rodzaju dostępu". Możesz przecież zrobić tak:
  1. <?php
  2. $config['user'] = array(
  3.   'resource/read' => true,
  4.   'resource/write' => true,
  5.   'resource/delete' => false
  6. );
  7. ?>

lub po prostu:
  1. <?php
  2. $config['user'] = array(
  3.   '*' => true,
  4.   'resource/delete' => false
  5. );
  6. ?>
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 19.08.2025 - 12:53