Clicky

Skocz do zawartości


Zdjęcie
- - - - -

[K2] ACL czyli kontrola uprawnień

16 odpowiedzi w tym temacie

  • Zaloguj się, aby dodać odpowiedź

#1 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 20 listopad 2008 - 21:44

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() {
if (is_null(self::$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['*']);
}
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 (!is_null($method)) {
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
<h3>Brak uprawnień!</h3>


Całą konfigurację należy zawrzeć w konfigu dla aplikacji tj. application/config/authorization.php
<?php
$config = array();

$config['user'] = array(
'*' => 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ń.

Proszę o uwagi oraz sugestie,
pion
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#2 marrek13

marrek13

    Początkujący

  • Użytkownik
  • Pip
  • 43 postów

Napisano 21 listopad 2008 - 20:23

W sumie znalazłem tylko jeden błąd - funkcja "instance" powinna być typu static ;)
Ogólnie rzecz biorąc miałem w zamierzeniu napisanie czegoś podobnego, lecz skłamałbym mówiąc, że coś identycznego. Nie ma się właściwie do czego doczepić - prostota ponad wszystko. Na pewno swoje zadanie spełni i wielu osobom się przyda - dobra robota ;)

#3 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 21 listopad 2008 - 21:08

W sumie znalazłem tylko jeden błąd - funkcja "instance" powinna być typu static ;)

O fak, racja. Poprawiłem, dzięki.

Nie ma się właściwie do czego doczepić - prostota ponad wszystko. Na pewno swoje zadanie spełni i wielu osobom się przyda - dobra robota ;)

Prostota była głównym priorytetem. Chciałem osiągnąć zamierzony efekt jak najprościej. Mam lekkiego "hopla" na punkcie wydajności więc wszystko co piszę staram się pisać jak najoptymalniej. Nie potrzeba mi większej funkcjonalności. Działa? Dziala - no i o to chodzi :) hehe.

Dzięki za pozytywną opinię.
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#4 Zepco

Zepco

    Senior Mastah

  • Moderator
  • 1583 postów
  • Skąd:Kielce

Napisano 21 listopad 2008 - 22:18

A co z konstruktorem?
Czy teraz nie jest możliwe utworzenie kilku instancji za pomocą new?
Ciekawa klasa.
Rozumiem, że można ją wykorzystać w połączeniu z Auth Kohany poprzez dodanie uprawnień w authorization_hook.php
	$acl->setRole('user');
?

OŚWIADCZENIE: Ja, niżej podpisany, świadomy wszystkich konsekwencji tego posta postanawiam go dopuścić do użytku publicznego, albowiem bo gdyż aczkolwiek uważam, że nie wyrządzi on (znaczy: post) krzywdy nikomu innemu niźli mnie samemu (czyli autorowi posta).
-- Zepco --


#5 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 22 listopad 2008 - 08:41

A co z konstruktorem?

Jest zbędny. Nie robiłby nic.

Czy teraz nie jest możliwe utworzenie kilku instancji za pomocą new?

Konstruktor nie jest zadeklarowany jako prywatny więc furtka takowa została zostawiona. Aczkolwiek ja osobiście korzystam tylko z jednej instancji klasy. Dlaczego? Gdyż zadaniem jej jest kontrola dostępu aktualnego użytkownika, nie potrzebuję kilku instancji klasy, w zupełności wystarcza jedna. Wszelkie pozostałe zawierałyby i tak te same dane.

Ciekawa klasa.

Dzięki.

Rozumiem, że można ją wykorzystać w połączeniu z Auth Kohany poprzez dodanie uprawnień w authorization_hook.php

	$acl->setRole('user');
?

Zapewne tak aczkolwiek sam nie korzystam z modułu Auth. Wystarczy przekazać do metody setRole nazwę typu użytkownika. Czy to będzie pobrane z sesji czy skądkolwiek indziej to nie ma większego znaczenia. Ja osobiście w tym miejscu korzystam ze swojej metody pobierającej typ usera z sesji ($session->getUserData('type')).

Wrócę jeszcze do kwestii: 1 obiekt vs X obiektów. Klasa ma również inny ciekawy ficzer ;) 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
$config = array();

$config['user'] = array(
'*' => true,
'cos' => false
);

application/controllers/jakiskontroler.php
public function index() {
if (Authorization::instance()->isAllowed('cos')) {
// dodatkowy kod
}
}


Zaletą korzystanai 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
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')) {
echo 'lalala tak';
}
else {
echo 'lalala nie';
}

// odebranie dostępu do zasobu "lalala"
$acl->deny('lalala');

if ($acl->isAllowed('lalala')) {
echo 'lalala tak';
}
else {
echo 'lalala nie';
}
}

Mam nadzieję, że powyższe przykłady ujawniają moc 8) tej w sumie niepozornej klasy :)
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#6 nrm

nrm

    webmastah

  • Admin
  • 1106 postów
  • Skąd:Katowice

Napisano 22 listopad 2008 - 12:58

fajnie fajnie, szkoda tylko, że wprowadzasz swoje kamelowe ;) nawyki z Sf tym samym zaburzając logikę i styl w K. ;) Nie chcę robić wojny co lepsze bo to każdy ma swoje nawyki, nie mniej używanie 2 konwencji w jednym projekcie prosi się o problemy ;)

#7 phpion

phpion

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 774 postów
  • Skąd:Sosnowiec, Dąbrowa Górnicza

Napisano 22 listopad 2008 - 13:16

fajnie fajnie, szkoda tylko, że wprowadzasz swoje kamelowe ;) nawyki z Sf tym samym zaburzając logikę i styl w K. ;)

Dzięki za zwrócenie na to uwagi. Nie pomyślałem o tym wcześniej. Jednak jak piszesz jest to nawyk. Będę musiał się go wyzbyć bo z S nie chcę mieć już raczej nic wspólnego. Za bardzo wkurzające hehe.
Notifero - Technologie Informatyczne | Warsztat: Kohana 3.x/2.x + PostgreSQL/MySQL | Programista Kohana

#8 jarek_bolo

jarek_bolo

    Początkujący

  • Użytkownik
  • Pip
  • 65 postów
  • Skąd:łódzkie

Napisano 27 listopad 2008 - 16:02

Fajna i nie trudna jak już się ją widzi klasa :)
Dobra robota.
Jam jest Polska, Ojczyzna Twoja, ziemia Ojców, z której wzrosłeś. Wszystko, czym jesteś, po Bogu - mnie zawdzięczasz!!

#9 r4zick

r4zick

    Młodszy Mastah

  • Użytkownik
  • PipPip
  • 234 postów

Napisano 31 grudzień 2008 - 20:05

Przydatne. Chociaż czasem zamiast wywalić 404 wywala 401. Np. gdy istnieje controller testowy a metoda download nie istnieje wywala 401.


#10 jarek_bolo

jarek_bolo

    Początkujący

  • Użytkownik
  • Pip
  • 65 postów
  • Skąd:łódzkie

Napisano 05 marzec 2009 - 18:58

Coś mi się zdaje, że hook powinien być dodany do system.post_routing, kiedy już znany jest kontroler i metoda.
Tak odkopuje, bo akurat krążę przy tematach około ACLowych :)
Jam jest Polska, Ojczyzna Twoja, ziemia Ojców, z której wzrosłeś. Wszystko, czym jesteś, po Bogu - mnie zawdzięczasz!!

#11 thejw23

thejw23

    Senior Mastah

  • Webmastahy
  • PipPipPip
  • 824 postów

Napisano 05 marzec 2009 - 19:20

moze komus sie przyda: http://blog.wolff-ha...management.html
na pierwszy rzut oka idea jest podobna do tej u phpion`a, drugi raz na razie nie zerkalem :)

EDIT:
jeszcze jeden tutorial: cz1 http://www.xaprb.com...control-in-sql/ cz2 http://www.xaprb.com...-in-sql-part-2/ niby ok, ale jak zobaczylem te przykladowe zapytania...

#12 thejw23

thejw23

    Senior Mastah

  • Webmastahy
  • PipPipPip
  • 824 postów

Napisano 13 marzec 2009 - 22:54

na bazie pomyslu phpion oraz przykladow z linkow powyzej przyszla mi do glowy taka oto struktura. jak skoncze to na pewno kod tu zmieszcze, ale moze jeszcze zanim skoncze ktos znajdzie jakis blad w zalozeniach :)

modul sklada sie z tabel:
- auth_users z istotnymi id oraz role_id. 1 user moze miec 1 role (albo jest adminem, albo userem albo guest...editor...whatever)
- auth_roles z ustalonymi rolami
- auth_users_access z uprawnieniami konkretnych uzytkownikow. 1 user moze miec wiele wpisow
- auth_roles_access z uprawnieniami konkretnych rol. 1 rola moze miec wiele wpisow

sam acl bazuje na nastepujacym szablonie, gdzie '-' oznacza zabranie uprawnien, * dowolny parametr:

(-)user_id/rola.kontroler.akcja

pierwszy parametr to role_id lub user_id, drugi to router::$controller czyli aktualnie uzywany kontroler, trzeci to read(czyli view)/delete/insert/update/whatever.

do auth_users_access mozna wpisac: marian.*.read (marian moze wszystko przegladac)
do auth_roles_access mozna dodac: admin.*.*  (admin moze wszystko)

inne przyklady to:
-marian.klienci.read  : marian klientow juz nie zobaczy
*.demo.* : kazdy ma dostep do wszystkiego w kontrolerze demo
itp itd.

jest to bardzo podobne do tego co jest w pierwszym poscie tego watku, ale wydaje mi sie, ze taka modyfikacja moze byc bardziej elastyczna. wystarczy jedna forma z kilkoma selectami w 1 linii aby dodac/edytowac uprawnienia i sprawnie je trzymac w bazie. podzial na 3 czesci (user/rola.kontroler.akcja) wydaje mi sie logiczny, nie wiem czy nawet nie lepiej zamiast akcji opierac sie od razu na metodach w kontrolerze. mozna przeciez skorzystac z Kohana::list_files('controllers', TRUE); polaczonym z  get_class_methods(). jedyny problem to fakt, ze nie wszyskie metody sa wywolywane bezposrednio, wiec nie moze ich zawierac select z lista metod w danym kontrolerze. oczywiscie zamiast nazwy kontrolera czy akcji mozna wpisac dowolny ciag znakow i w ten sposob sprawdzac sobie uprawnienia np. dla poszczegolnych czesci kontrolera.

co o tym myslicie? caly czas mam wrazenie, ze cos przegapilem, cos mi umknelo i pomysl nie jest wcale taki fajny jak mi sie wydaje.

#13 tryhp3

tryhp3

    Początkujący

  • Użytkownik
  • Pip
  • 20 postów

Napisano 09 kwiecień 2010 - 20:53

fajna klasa

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

czyli co trzeba zrobić?:)
mam kohana 2.3.4

Edit:
wyczaiłem zaraz po napisaniu posta, dla potomnych, zmieniamy w pliku application/config.php
hooki:
z FALSE na TRUE
$config['render_stats'] = TRUE;


moduły:
$config['modules'] = array
(
.....
          //dopisujemy
          MODPATH.'authorization', // ACL
          ....
);



#14 jaskooo

jaskooo

    Początkujący

  • Użytkownik
  • Pip
  • 7 postów

Napisano 27 lipiec 2010 - 09:21

Cześć, a do Kohanej v3 jest jakis modół ACL?

#15 mck

mck

    Jestę Blogerę

  • Admin
  • 1544 postów

Napisano 27 lipiec 2010 - 10:45

modółu raczej nie ma, ale jakiś moduł pewnie się znajdzie...

#16 Maciek

Maciek

    Senior Mastah

  • Użytkownik
  • PipPipPip
  • 780 postów

Napisano 27 lipiec 2010 - 11:36

Cześć, a do Kohanej v3 jest jakis modół ACL?


Przypominam również, że na tym forum jest specjalna część poświęcona tylko KO3 i w niej jest dział z modułami. Znajduje się tam przyklejony post z linkiem do zebranych modułów do KO3. Warto czasem użyć scroll'a myszki.

#17 dreaken

dreaken

    Początkujący

  • Użytkownik
  • Pip
  • 4 postów

Napisano 13 wrzesień 2010 - 14:59

Można to użyć na bardziej pojedyncze przypadki ? tzn np:
'administrate/news/edit/*' => false

Albo

'news/view/28' => false

??




Użytkownicy przeglądający ten temat: 0

0 użytkowników, 0 gości, 0 anonimowych