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<?php
/**
* Klasa realizująca obsługę uprawnień w systemie.
*
* @package authorization
*/
class Authorization {
/**
* Instancja klasy Authorization.
*
* @var Authorization
*/
private static $instance = null;
/**
* Nazwa roli aktualnego użytkownika.
*
* @var string
*/
private $role;
/**
* Tablica uprawnień.
*
* @var array
*/
private $credentials = array();
/**
* Domyślna wartość uprawnień.
*
* @var boolean
*/
private $default;
/**
* Zwraca instancję klasy Authorization
*
* @return Authorization
*/
public static function instance
() { self::$instance = new Authorization();
}
return self::$instance;
}
/**
* Wczytuje konfigurację uprawnień z pliku zewnętrznego.
*
* Dodatkowo ustawia domyślną wartość o ile została ustalona w pliku konfiguracyjnym.
*/
public function loadConfig() {
$this->credentials = (array)Kohana
::config('authorization.'.$this->role);
if (isset($this->credentials[self::DEFAULT_KEY])) { $this->default = (bool)$this->credentials[self::DEFAULT_KEY];
unset($this->credentials[self::DEFAULT_KEY]); }
else {
$this->default = self::DEFAULT_VALUE;
}
}
/**
* Dodaje uprawnienia do danego zasobu.
*
* @param string $resource Nazwa zasobu.
*/
public function allow($resource) {
$this->credentials[$resource] = true;
}
/**
* Odbiera uprawnienia do danego zasobu.
*
* @param string $resource Nazwa zasobu.
*/
public function deny($resource) {
$this->credentials[$resource] = false;
}
/**
* Sprawdza, czy użytkownik ma prawo dostępu do danego zasobu.
*
* W przypadku podania drugiego parametru ($method) zasób traktowany jest jako żądanie akcji kontrolera.
*
* Sprawdzanie odbywa się w kilku etapach:
* - przypisanie wartości domyślnej,
* - sprawdzenie globalnego ustawienia dla kontrolera (w przypadku akcji),
* - sprawdzenie konkretnego zasobu.
*
* Zwracana wartość jest nadpisywana nową wartością w kolejnych etapach sprawdzania.
*
* @param string $resource Nazwa zasobu.
* @param string $method Opcjonalna nazwa akcji kontrolera.
* @return boolean
*/
public function isAllowed($resource, $method = null) {
$return = $this->default;
if (isset($this->credentials[$resource.self::SEPARATOR.self::DEFAULT_KEY])) { $return = (bool)$this->credentials[$resource.self::SEPARATOR.self::DEFAULT_KEY];
}
$resource .= self::SEPARATOR.$method;
}
if (isset($this->credentials[$resource])) { $return = (bool)$this->credentials[$resource];
}
return $return;
}
public function setRole($v) {
$this->role = $v;
}
public function getRole() {
return $this->role;
}
public function setCredentials
(array $v = array()) { $this->credentials = $v;
}
public function getCredentials() {
return $this->credentials;
}
/**
* Wartość domyślna dla uprawnień.
*
* @var boolean
*/
const DEFAULT_VALUE = false;
/**
* Klucz oznaczający elementy domyślne.
*
* @var string
*/
const DEFAULT_KEY = '*';
/**
* Separator kontrolera oraz akcji.
*
* @var string
*/
const SEPARATOR = '/';
}
?>
application/modules/authorization/hooks/authorization_hook.php<?php
/**
* Hook realizujący zabezpieczenie autoryzacji dostępu.
*
* @package authorization
*/
class Authorization_Hook {
/**
* Sprawdza czy dany użytkownik ma prawo dostępu do danej akcji kontrolera.
*
* W przypadku braku uprawnień wyświetla stronę z odpowiednim komunikatem.
*
*/
public function check() {
$acl = Authorization::instance();
$acl->setRole('user'); // docelowo pobierane z sesji
$acl->loadConfig();
if (!$acl->isAllowed(Router::$controller, Router::$method)) {
Event
::add('system.401', array('Authorization_Hook', 'error')); Event::run('system.401');
}
}
/**
* Przekierowuje żądanie do strony z błędem braku dostępu.
*
*/
public function error() {
Router::$controller = 'authorization';
Router::$method = 'error_401';
Router
::$arguments = array(); }
}
Event
::add('system.routing', array('Authorization_Hook', 'check'));?>
application/modules/authorization/controllers/authorization.php<?php
/**
* @package authorization
*/
class Authorization_Controller extends Main_Controller_Core {
public function error_401() {
$this->template->content = new View('authorization/error_401');
}
}
?>
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<?php
<h3>Brak uprawnień!</h3>
?>
Całą konfigurację należy zawrzeć w konfigu dla aplikacji tj.
application/config/authorization.php<?php
'*' => false,
'authentication/*' => true,
'authentication/logout' => false
);
$config['admin'] = array( '*' => true
);
?>
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ć

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<?php
'*' => true,
'cos' => false
);
?>
application/controllers/jakiskontroler.php<?php
public function index() {
if (Authorization::instance()->isAllowed('cos')) {
// dodatkowy kod
}
}
?>
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<?php
public function index() {
// utworzenie nowego obiektu
$acl = new Authorization();
// przypisanie roli
$acl->setRole('mietek');
// zezwolenie na dostęp do zasobu "lalala"
$acl->allow('lalala');
if ($acl->isAllowed('lalala')) {
}
else {
}
// odebranie dostępu do zasobu "lalala"
$acl->deny('lalala');
if ($acl->isAllowed('lalala')) {
}
else {
}
}
?>
Proszę o opinie.
pion
Ten post edytował phpion 1.12.2008, 17:12:07