Witam. Jestem bardzo początkujący w temacie php, ale duużżżooo czytam i zacząłem od jakiegoś czasu rozwijać swój framework i tutaj na forum chciałbym zaprezentować swoje przemyślenia na temat ACL jakie zastosowałem. Otóż w żadnym znanym mi frameworku (Zend, Cake, Symfony, Code Igniter, Kohana) nie umiałem łatwo i szybko zaimplementować takiej jakby automatycznej autoryzacji użytkownika chodziło mi o sprawdzenie praw dostępu do zasobu już na poziomie front-controllera, który zobaczy czy w Liście Kontroli Dostępu znajduje się żądany zasób dla obecnej roli użytkownika i albo 'wpuszcza' go i włącza odpowiednią akcje controllera albo nie 'wpuszcza' i kieruje na wiadomość o braku dostępu. Wydaje mi się to lepszym rozwiązaniem niż pisanie w controllerach instrukcji if i else za każdym razem. Oto jak to jest zaimplementowane:
We folderze config trzymam sobie prosty plik xml, który wgląda następująco:
<?xml version="1.0" encoding="UTF-8"?>
<acl>
<guest>
<resource name="/" label="Strona główna" />
<resource name="/user/login" label="Zaloguj się" />
<resource name="/user/register" label="Zarejestruj się" />
</guest>
<user>
<resource name="/user/logout" label="Wyloguj się" />
<resource name="/user/login" label="" />
<resource name="/user/register" label="" />
</user>
<moderator>
</moderator>
<admin>
</admin>
</acl>
jak widać chyba nic nie trzeba tutaj tłumaczyć, jedyne co może wzbudzać zainteresowanie to dlaczego w roli user zasoby /user/login i user/register maja pusty label, ale to później wytłumaczę, bo jest jeszcze jedna funkcjonalność tego podejścia, o której za chwile napisze.
A tak wygląda kod:
//najpierw potrzebujemy role, jest ona brana z bazy, a jeśli nie to domyślną jest guest
$rola = (isset($_SESSION['user']['rola'])) ?
$_SESSION['user']['rola'] : 'guest';
//teraz w obiekt acl pobieramy wcześniejszy plik xml
$acl = simplexml_load_file('../config/acl.xml');
//budujemy tablice dwuwymiarową z rolami i odpowiadającymi im zasobami z pliku xml
foreach($acl as $role) {
foreach($role as $res) {
$label = (string)$res['label'];
$ACL[$role->getName()][(string)$res['name']] = ($label == '') ? null : $label;
}
}
//teraz czas na funkcje, która tworzy powiązania (dziedziczenie) ról jakie chcemy ze sobą
//oraz tworzy nam na podstawie powiązań nawigacje gotową dla obecnie zalogowanego użytkownika z odpowiednią rolą
//tutaj właśnie są nam potrzebne te puste atrybuty 'label' w zasobach, bo po co mamy wyświetlać zalogowanemu użytkownikowi
//linki do zalogowania albo do zarejestrowania się, skoro on już to zrobił :) Dajemy mu tylko możliwość do wylogowania. :)
//funkcja po prostu wyrzuca sobie takie powtarzające się zasoby z pustymi labelami i daje Nam ładną tablicę z nawigacją.
function setInheritAndNav () {
foreach($args as $key => $val) {
if($val == null) {
}
}
foreach($args as $tab) {
$newArgs[] = $tab;
}
foreach($newArgs as $tab) {
if($tab != null) {
}
}
foreach($nav as $key => $val) {
if($val == null) {
}
}
return $nav;
}
//tutaj w prosty sposób definiujemy sobie jakie role jak mają zostać dziedziczone
//korzystając z wyżej wymienionej funkcji, dziedziczenie działa od lewej strony, czyli
//tak jak np. dla admina: admin -> moderator -> user -> guest ('->' oznacza 'dziedziczy po'),
//a nawet mozemy zrobic tak guest -> user -> moderator -> admin :) wtedy guest dziedziczy po naszych wszystkich rolach :)
$guest = setInheritAndNav($ACL['guest']);
$user = setInheritAndNav($ACL['user'], $ACL['guest']);
$admin = setInheritAndNav($ACL['admin'], $ACL['moderator'], $ACL['user'], $ACL['guest']);
//tworzymy sobie dwuwymiarową tablicę z nawigacjami dla ról
$NAV = array('guest' => $guest, 'user' => $user, 'admin' => $admin);
//żeby w prosty sposób sprawdzić sobie właśnie czy żądany zasób znajduje się ACL:
//i działanie prostego front-controllera:
//w adresie trzymam zmienną url, która przechowuje mi kombinację czystych urli np. '/index/index/' lub '/user/login' albo nic czyli '/' itp.
$_controller = $urlArray[0] ? $urlArray[0] : 'index';
$_action = $urlArray[1] ? $urlArray[1] : 'index';
$_parameter = $urlArray[2] ? $urlArray[2] : '1';
if(in_array('/'.$_controller.'/'.$_action, $resources) || in_array('/', $resources)) {
$controllerName = ucfirst($_controller).'Controller';
$run = new $controllerName($_controller, $_action, $NAV[$rola]);
$run->$_action($_parameter);
}
else
{
URL::_redirect();
}
prawie wszystko dzieje się metodą strukturalną, bo po co obciążać cały system obiektówką, tam gdzie nie jest ona potrzebna (IMG:
style_emoticons/default/smile.gif) .
Chciałbym usłyszeć jakieś opinie lub uwagi co można jeszcze poprawić, usprawnić lub zmienić.