Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: cojack, dodany: 22.01.2010 10:41, tagi: php

Tak więc w poprzednim wpisie, pokazałem w jaki sposób zaimplementować taką strukturę w sql, w tym wpisie chciałbym rozważyć pewne dodatkowe możliwości, które mogą chodź nie muszą okazać się przydatne w cale. A więc, mamy tutaj sprawdzanie uprawnień tylko i wyłącznie dla grup użytkowników. Co nie było naszym założeniem, więc by kontynuować i rozszerzyć możliwości naszego rbac’a należy wprowadzić pewne zmiany. Tabela rbac_privilages powinna zostać przemianowana na rbac_group_privilages, musimy też utworzyć drugą tabelę rbac_user_privilages o podobnej strukturze jak ta poprzednia. Taka zmiana pozwoli nam już dodawać indywidualne uprawnienia dla użytkowników. Z założeń pozostało nam jeszcze grupa do grup zadań czyli naszych controllerów, oraz użytkownik do grupy zadań. Jakby nie patrzeć są to dodatkowe dwie tabele, których utworzenie nie powinno przysporzyć większych problemów.

Logika struktury sql

Można by się zapytać po co tyle tabel? A bardzo chętnie na to pytanie odpowiem, otóż baza danych nie jest stworzona po to by trzymać w niej to co się chce i nawet bez sensu, takie rzeczy dyskryminują nas od razu w oczach pracodawcy. Więc dane nie powinny się powtarzać, kolumny powinny być tak tworzone by zawierały jak najmniej wartości NULL chyba że ma to pewien sens. Coś na zasadzie “Dziel i zwyciężaj” tylko tutaj prawda nie mamy żadnych algorytmów :)

Priorytety w Role Based Access Control

Mamy taki problem: Czy pobrać wszystko za jednym zamachem i sprawdzać dostęp za pomocą tego co mamy, czy sprawdzać pobierając dane po kolei? I odpowiedź bez sprawdzenia tego, które z założeń jest szybsze jest chyba absurdem, niestety nie mam na razie na to czasu by to sprawdzić, lecz chciałbym ustalić kolejność priorytetów. Założenie jest takie: Każdy użytkownik jest przypisany do jakiejś grupy, użytkownik bez grupy też jest w grupie użytkowników a mowa tutaj o osobach które nie są zarejestrowane na naszej stronie, można przyjąć ich za grupę Guest, czyli gości. Taki paradoks. I teraz priorytety wg mnie można by ustalić w ten sposób:

  1. Sprawdzanie czy grupa ma dostęp do controllera, czyli naszej grupy zadań.
    1. Ma, sprawdzamy czy grupa ma dostęp do akcji w kontrolerze, czyli naszego zadania
      1. Ma, zezwalamy
      2. Nie ma, przechodzimy do pkt 2
    2. Nie ma, przechodzimy do pkt 2
  2. Grupa nie ma uprawnień do zadania w controllerze, sprawdzamy czy użytkownik ma dostęp do controllera
    1. Ma, sprawdzamy czy ma dostęp do akcji w kontrolerze
      1. Ma, zezwalamy
      2. Nie ma, odmawiamy
    2. Nie ma, odmawiamy
  3. Amen

Hierarchia, czyli dziedziczenie uprawnień

Szczerze jak sobie pomyślę o takim założeniu to zaczyna mnie głowa boleć, bo już sobie w głowie tworzę taką aplikację w sql która musi to sprawdzać, no daję głowę, szczęka opada… Więc nie wiem czy aby na pewno jest to słuszne by tworzyć to, ale słowo się rzekło, to i się to napisze. Tylko obawiam się że bez rekurencji to nie przejdzie, chociaż nie jestem tego jeszcze do końca pewien, być może nie będzie tak źle na jak to wygląda. Dodatkowe akcje wchodzą w grę, należy sprawdzać czy jeżeli np grupa nie ma uprawnień do akcji, czy nad grupa ma pozwolenie na tą akcję oraz czy pozwala ją dziedziczyć, gdyby ktoś wyjechał z pomysłem komu pozwala ją dziedziczyć to w ogóle jeszcze więcej roboty, więc proszę nie dobijać leżącego :) Huh chociaż dobrze że nie ma sensu robić hierarchie użytkowników, bo od tego jest rbac właśnie by zrobił to za nas.

Słów kilka na zakończenie

Myślę że jest to optymalne sprawdzanie, chyba że coś pominąłem to mnie poprawcie, trochę z rana mogę być jeszcze nie ogarnięty z wszystkim, więc pisać w komentarzach co i jak.

Autor wpisu: thejw23, dodany: 19.01.2010 22:43, tagi: php

Inclued jest ciekawym rozszerzeniem php pozwalajacym zrzut do pliku informacji na temat includowanych plikow. nie jest to zazwyczaj do niczego niezbedne, ale czasami milo popatrzec na takie wykresy, aby moc ocenic stopien komplikacji frameworkow czy rozwiazan eccomerce (lub wlasnych CMSow itd).zrodla rozszerzenia sa dostepne np. na stronie domowej autora (wersja 0.3), a w sieci jest kilka przykladow jak to zrobic pod linuxem (np. tutaj), jednak nigdzie nie znalazlem informacji na temat uchomienia tego pod windowsem. juz mialem kompilowac, ale w koncu udalo wyszperac gotowa wersje, w postaci pliku dll. calosc testowana na xampp z php 5.3. tak wiec:1) pobieramy z tego adresu odpowiednia wersje pliku. szukamy plikow 'php_inclued-' z odpowiednia dla nas koncowka. phpinfo() prawde powie, u mnie to bylo php_inclued-5.3-svn20091211-VC6-x86.zip (ew. wersja z VC9, nie pamietam, na pewno wersja 'nts')2) dodajemy w php.ini nowy wpis 'extension=php_inclued.dll' oraz 'inclued.enabled = On' - nie dodajemy inclued.dumpdir, u mnie to nie chcialo dzialac, generowalo puste pliki.3) restart apache i mozna testowac4) w wybranym pliku bedacym punktem wejscia* do frameworka czy innego systemu (zazwyczaj index.php) dodajemy na samym koncu:$fp = fopen("dump.me", "w");fwrite($fp, serialize(inclued_get_data()));fclose($fp);co stworzy/nadpisze plik dump.me i doda do niego zrzut includowanych klas. nastepnie uruchamiamy przegladarke, wchodzimy na strone, a jak sie zaladuje, sprawdzamy czy jest plik dump.me,teraz potrzebujemy plik gengraph.php, do sciagniecia wraz ze zrodlami inclued czyli tutaj. uruchamiamy go z lini polecen, cmd i pozniej: php.exe /sciezka/do/pliku/gengraph.php -i /sciezka/do/pliku/dump.mew efekcie otrzymamy plik inclued.out.dot - polowa sukcesu za nami. teraz potrzebny jest Graphviz, ktory to pobieramy i instalujemy. dzieki niemu przerobimy .dot na ladny wykres. po zainstalowaniu Graphviz przechodzimy do katalogu gdzie jest zainstalowany, nastepnie do bin i uruchamiamy z linii polecen:dot -Tpng -o inclued.png /sciezka/do/pliku/inclued.out.doto i mozemy cieszyc sie wykresami. przyklady wygenerowane dla:KohanaPHP 2.3.4 - clickKohanaPHP 2.4RC2 - clickKohanaPHP 3.0.3  - clicknie sa to schematy idealne. wygenerowane sa na podstawie stron startowych frameworka, ktore nie korzystaja z bazy danych, a 3.0.3 nie korzysta z prawie niczego (co nie zmienia faktu, ze jest to bardzo czysty wykres i dobrze przemyslany framework).

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: cojack, dodany: 19.01.2010 20:57, tagi: sql

Nadszedł czas na pierwszą implementację tej struktury w sql, oczywiście nie jest to czego byśmy oczekiwali ponieważ ma pewne braki które mogły by się wydawać dla większego użytku wprost odwrotnie proporcjonalne do zastosowania role based access control. Otóż jest trochę uproszczona struktura, dlaczego? Mieliśmy w pracy z kolegą burzę mózgów na ten temat gdyż go bardzo zainteresował i doszedł do wniosku iż konstruowanie kolosa może mieć negatywny wpływ na jego interfejs, i prawdę powiedziawszy po głębszym zastanowieniu się oraz doświadczeniu wyniesionym z używania phpbb (taki skrypt forum) doszedłem do wniosku iż ma chłop rację. Więc na pierwszy ogień skonstruowaliśmy taką oto strukturę rbac’a, ale moje ego nie pozwala mi na zakończenie prac nad tym i będę kontynuował rozwój do takiego stopnia że stwierdzę iż większego kolosa się zbudować nie da ponieważ zawiera już wszystko.

Struktura SQL Role Based Access Control

Także do dzieła, struktura bazy danych:

BEGIN;
 
DROP TABLE IF EXISTS "rbac_user" CASCADE;
CREATE TABLE "rbac_user"
(
   "idUser" SERIAL PRIMARY KEY,
   "userName" VARCHAR( 255 ) NOT NULL
);
 
DROP TABLE IF EXISTS "rbac_group" CASCADE;
CREATE TABLE "rbac_group"
(
   "idGroup" SERIAL PRIMARY KEY,
   "groupName" VARCHAR( 255 ) UNIQUE NOT NULL
);
 
DROP TABLE IF EXISTS "rbac_user_to_group";
CREATE TABLE "rbac_user_to_group"
(
   "idUser" INT REFERENCES "rbac_user"( "idUser" ) NOT NULL,
   "idGroup" INT REFERENCES "rbac_group"( "idGroup" ) NOT NULL,
   PRIMARY KEY( "idUser", "idGroup" )
);
 
DROP TABLE IF EXISTS "rbac_module" CASCADE;
CREATE TABLE "rbac_module"
(
   "idModule" SERIAL PRIMARY KEY,
   "moduleName" VARCHAR( 255 ) UNIQUE NOT NULL
);
 
DROP TABLE IF EXISTS "rbac_action" CASCADE;
CREATE TABLE "rbac_action"
(
   "idAction" SERIAL PRIMARY KEY,
   "idModule" INT REFERENCES "rbac_module"( "idModule" ) NOT NULL,
   "actionName" VARCHAR( 255 ) NOT NULL,
   "inherited" BOOLEAN DEFAULT FALSE NOT NULL,
   UNIQUE( "actionName", "idModule" )
);
 
DROP TABLE IF EXISTS "rbac_privilages";
CREATE TABLE "rbac_privilages"
(
   "idGroup" INT REFERENCES "rbac_group"( "idGroup" ) NOT NULL,
   "idModule" INT REFERENCES "rbac_module"( "idModule" ) NOT NULL,
   "idAction" INT REFERENCES "rbac_action"( "idAction" ) NOT NULL,
   "allow" BOOLEAN DEFAULT FALSE NOT NULL,
   PRIMARY KEY( "idGroup", "idModule", "idAction" )
);
 
COMMIT;

Użyłem transakcji, w posgresql można ;) W MySQL też, pod warunkiem że typ tabeli to InnoDB. Ale nie teraz o tym rzecz. Co jest co?

rbac_user – tabela przechowująca użytkowników naszego systemu rbac_group – tabela przechowująca grupy w naszym systemie rbac_user_to_group – tabela wiążąca użytkowników z grupami, relacja typu many-to-many (wiele do wielu) rbac_module – tabela przechowująca nazwy naszych modułów, można to rozumieć jako controllery naszej aplikacji rbac_action – tabela przechowująca nazwy naszych akcji, trzeba to rozumieć jako metody w naszych controllerach, relacja typu many-to-one (wiele do jednego, to samo co jeden do wielu [one-to-many]) rbac_privilages – a to jest tabela wiążąca grupę użytkowników, moduł i akcję.

Demo Role Based Access Control

Teraz jak to ustrojstwo wypełnić danymi? Bardzo proszę:

BEGIN;
 
INSERT INTO "rbac_user" ( "userName" ) VALUES ( 'przemek' ), ( 'maciej' ), ( 'andrzej' ), ( 'grzesiek' );
INSERT INTO "rbac_group" ( "groupName" ) VALUES ( 'admin' ), ( 'user' ), ( 'moderator' );
INSERT INTO "rbac_user_to_group" VALUES ( 1, 1 ), ( 2, 3 ), ( 3, 2 ), ( 4, 2 );
INSERT INTO "rbac_module" ( "moduleName" ) VALUES ( 'news' ), ( 'articles' ), ( 'download' ), ( 'music' );
INSERT INTO "rbac_action" ( "idModule", "actionName", "inherited" ) VALUES
   ( 1, 'index', FALSE ),
   ( 1, 'edit', FALSE ),
   ( 1, 'add', FALSE ),
   ( 1, 'delete', FALSE ),
   ( 1, 'block', FALSE ),
   ( 2, 'index', TRUE ),
   ( 2, 'edit', TRUE ),
   ( 2, 'add', TRUE ),
   ( 2, 'delete', TRUE ),
   ( 2, 'block', TRUE ),
   ( 3, 'index', TRUE ),
   ( 3, 'edit', FALSE ),
   ( 3, 'add', TRUE ),
   ( 3, 'delete', FALSE ),
   ( 3, 'block', FALSE ),
   ( 3, 'download', TRUE ),   
   ( 4, 'index', TRUE ),
   ( 4, 'edit', TRUE ),
   ( 4, 'add', FALSE ),
   ( 4, 'delete', FALSE ),
   ( 4, 'block', FALSE ),
   ( 4, 'download', FALSE ),
   ( 4, 'play', TRUE );
 
INSERT INTO "rbac_privilages" VALUES 
   ( 1, 1, 1, TRUE ),
   ( 1, 1, 2, TRUE ),
   ( 1, 1, 3, TRUE ),
   ( 1, 1, 4, TRUE ),
   ( 1, 1, 5, TRUE ),
   ( 2, 1, 1, TRUE ),
   ( 2, 1, 2, FALSE ),
   ( 2, 1, 3, TRUE ),
   ( 2, 1, 4, FALSE ),
   ( 2, 1, 5, FALSE ),
   ( 3, 1, 1, TRUE ),
   ( 3, 1, 2, TRUE ),
   ( 3, 1, 3, TRUE ),
   ( 3, 1, 4, TRUE ),
   ( 3, 1, 5, FALSE ),
   ( 1, 2, 6, TRUE ),
   ( 1, 2, 7, TRUE ),
   ( 1, 2, 8, TRUE ),
   ( 1, 2, 9, TRUE ),
   ( 1, 2, 10, TRUE ),
   ( 2, 2, 6, TRUE ),
   ( 2, 2, 7, FALSE ),
   ( 2, 2, 8, TRUE ),
   ( 2, 2, 9, FALSE ),
   ( 2, 2, 10, FALSE ),
   ( 3, 2, 6, TRUE ),
   ( 3, 2, 7, TRUE ),
   ( 3, 2, 8, TRUE ),
   ( 3, 2, 9, TRUE ),
   ( 3, 2, 10, FALSE ),
   ( 1, 3, 11, TRUE ),
   ( 1, 3, 12, TRUE ),
   ( 1, 3, 13, TRUE ),
   ( 1, 3, 14, TRUE ),
   ( 1, 3, 15, TRUE ),
   ( 1, 3, 16, TRUE ),
   ( 2, 3, 11, TRUE ),
   ( 2, 3, 12, FALSE ),
   ( 2, 3, 13, TRUE ),
   ( 2, 3, 14, FALSE ),
   ( 2, 3, 15, FALSE ),
   ( 2, 3, 16, TRUE ),
   ( 3, 3, 11, TRUE ),
   ( 3, 3, 12, TRUE ),
   ( 3, 3, 13, TRUE ),
   ( 3, 3, 14, FALSE ),
   ( 3, 3, 15, TRUE ),
   ( 3, 3, 16, TRUE ),
   ( 1, 4, 17, TRUE ),
   ( 1, 4, 18, TRUE ),
   ( 1, 4, 19, TRUE ),
   ( 1, 4, 20, TRUE ),
   ( 1, 4, 21, TRUE ),
   ( 1, 4, 22, TRUE ),
   ( 1, 4, 23, TRUE ),
   ( 2, 4, 17, TRUE ),
   ( 2, 4, 18, FALSE ),
   ( 2, 4, 19, TRUE ),
   ( 2, 4, 20, FALSE ),
   ( 2, 4, 21, FALSE ),
   ( 2, 4, 22, TRUE ),
   ( 2, 4, 23, TRUE ),
   ( 3, 4, 17, TRUE ),
   ( 3, 4, 18, TRUE ),
   ( 3, 4, 19, TRUE ),
   ( 3, 4, 20, FALSE ),
   ( 3, 4, 21, TRUE ),
   ( 3, 4, 22, TRUE ),
   ( 3, 4, 23, TRUE );
 
COMMIT;

Znowu transakcję, jakoś tak szybciej działa to ;) Jak pewnie zdążyliście zauważyć tabela rbac_action posiada kolumnę “inherited” która w późniejszym etapie mojej implementacji tego paradygmatu będzie potrzebna do tego by w hierarchii definiować czy dana akcja ma być dziedziczona dla pod grup. Taki ficzer.

Teraz tak, żeby to działało co jest wyżej przedstawione na gotowca, czyli copy-paste wymagana jest baza danych postgresql > 8.2. Dlaczego? A otóż dlatego że:

DROP "tabela" IF EXISTS;

jest zaimplementowane od tej versji. Oj brakowało tego brakowało… Nie wiem jak z wierszami podawanymi po przecinku, gdyż w 8.1 to nie działa (mowa tutaj o klauzuli INSERT).

Sprawdzanie uprawnień

Pozostało nam już tylko jak to pobrać, dla przykładu nie tworzyłem żadnych testów wydajnościowych, chodź przyznam że łączymy parę tabel ale utworzone indeksy są w pełni wykorzystywane, przykład jak sprawdzić uprawnienia:

SELECT 
  "allow" 
FROM 
  "rbac_privilages" p 
LEFT JOIN 
  "rbac_module" m 
ON 
  ( p."idModule" = m."idModule" ) 
LEFT JOIN 
  "rbac_action" a 
ON 
  ( p."idAction" = a."idAction" ) 
LEFT JOIN 
  "rbac_user_to_group" u2g 
ON 
  ( p."idGroup" = u2g."idGroup" ) 
WHERE 
  u2g."idUser" = 2 
AND 
  m."moduleName" = 'music' 
AND 
  a."actionName" = 'index';

Możemy sobie z tego ładny widoczek utworzyć, ale może o tym kiedy indziej. A teraz co wykazało explain?

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Damian Tylczyński, dodany: 16.01.2010 18:08, tagi: internet, php

Przemyślenia dot. aktualnego modelu projektowania aplikacji internetowych i propozycja jego uporządkowania.

Autor wpisu: batman, dodany: 16.01.2010 10:25, tagi: zend_framework

Wczoraj (15.01.2010) światło dzienne ujrzała pierwsza beta nowej wersji Zend Framerowka, oznaczona numerem 1.10. Spośród licznych zmian moją uwagę przykuła informacja o zmianach jakie zaszły w Zend_Tool. Od wersji 1.10, oprócz poprzednich opcji, mamy możliwość: wygenerować klasę formularza (zf.bat create form name module) – niestety tylko klasę. Nie znalazłem nigdzie informacji o możliwości

Autor wpisu: batman, dodany: 15.01.2010 10:09, tagi: javascript, jquery

Wczoraj (14.01.2010) została wydana nowa wersja popularnej biblioteki jQuery, oznaczona numerem 1.4.  Wprawdzie nowa wersja nie wnosi rewolucyjnych usprawnień, jednak nie sposób nie zauważyć jej nowych możliwości: zwiększenie wydajności poprzez przepisanie najczęściej wykorzystywanych funkcji dodanie obsługi funkcji do sporej ilości metod ustawiających (setter functions), takich jak .css()

Autor wpisu: batman, dodany: 14.01.2010 15:41, tagi: zend_framework

Zend_Navigation idealnie nadaje się do stron z prostym menu. Niestety najmniejsze odstępstwo od schematu powoduje, iż praca z tym komponentem to droga przez mękę. Przykładem takiej męki może być próba wyrenderowania submenu oraz breadcrumbs w taki sposób, że breadcrumbs zawiera element, którego nie ma w menu. Standardowo nie znalazłem rozwiązania w manualu (co nie oznacza, że go tam nie ma –
Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.