Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: System uprawnień - organizacja kodu
Forum PHP.pl > Forum > PHP > Object-oriented programming
404
Witam!
Stworzyłem sobie prosty system uprawnień i zastanawiam się nad organizacją kodu...
  1. class SSE_Group
  2. {
  3. private $db,
  4. $id,
  5. $hash,
  6. $name;
  7.  
  8. public function getId();
  9. public function setId();
  10.  
  11. //...
  12.  
  13. };

  1. class SSE_GroupArray
  2. {
  3. public $groupsArray = array();
  4. };

  1. class SSE_GroupDatabase : public JakasKlasaDoObslugiBazyDanych
  2. {
  3. private $db;
  4.  
  5. public function insert(SSE_Group $group);
  6. public function delete($groupId);
  7. public function select(SSE_GroupArray &$groups);
  8. public function update(SSE_Group $group);
  9.  
  10. //...
  11. };

Wiem, że to mój kod, wiem, że "powinienem pisać tak jak umiem", ale prosiłbym o jakieś wskazówki bądź przykłady rozwiązań w waszych aplikacjach smile.gif Ogólnie rzecz biorąc to chciałbym, aby ten kod był elastyczny i w miarę łatwy w rozwoju.
by_ikar
Tak więc, ja tworząc klasę do obsługi użytkownika, stworzyłem do niej od razu cały zestaw klas które razem z tą klasą User współgrają. Czyli Authentication, UserManager (aktualizacja usera, szukanie usera według kryteriów, tworzenie nowego usera itp), Group oraz GroupManager. Klasa User posiada właściwość $role, która może posiadać tylko jedną z 3 podstawowych roli (ROLE_GUEST, ROLE_USER, ROLE_ADMIN). Domyślnie ROLE_GUEST. Każda grupa może mieć jakieś swoje role, użytkownik może należeć do różnych grup, a każda grupa może mieć przypisane różne uprawnienia, uprawnienia różne niż te 3 podstawowe. Czyli np uprawnienia dla moderatorów, redaktorów itp. Podczas autoryzacji, UserManager pobiera z bazy dane (podstawowe dane, opcjonalne dane, oraz wszystkie grupy do których należy użytkownik), te dane są przekazywane do klasy User. A ona w konstruktorze sobie te dane odpowiednio dzieli/łączy i przypisuje do odpowiednich właściwości. Mając wszystkie grupy do których należy użytkownik, mam uprawnienia tych wszystkich grup. Z całości powstaje tablica, która jest przypisana do właściwości $_roles. W klasie mam metodę hasRole(mixed $role), która przeszukuje tą wspólną tablicę w poszukiwaniu podanych w argumencie roli i zwracając true/false. Na samym początku sprawdzając czy w tej tablicy nie istnieje ROLE_ADMIN, jeżeli tak return true, jeżeli nie, to przeszukiwana jest tablica pod kontem roli, podanej w argumencie.

Trochę pewnie pokręciłem, ale mam nadzieje że chodź część z mojego bełkotu zrozumiesz wink.gif

EDIT: nie wiedziałem czy mój post się wczoraj dodał, bo niestety forum padło..
404
Właście zauważyłem, że wczoraj coś było nie tak z forum, ale udało mi się odczytać post smile.gif

No cóż..., czyli tyle rozwiązań ilu programistów smile.gif Ja to trochę inaczej sobie nabazgrałem. Użytkownikowi przypisuję grupę, a grupie role. Grupę użytkownika (jej id) przechowuję w klasie UserProfile, a potem:
  1. $sse = new SSE($db, $userProfile->getGroupId());
  2. $sse->initialization();
  3. if( $sse->isAllowed('www/admin/projects/add) )
  4. {
  5. echo 'Hello!';
  6. }else
  7. {
  8. echo 'Access denied!';
  9. }

Ogólnie to mój problem sprowadza się do poprawnego, zgodnego z OOP zaprojektowania aplikacji. Dlatego prosiłem o przykłady żebym mógł zobaczyć jak to robią bardziej zaawansowani programiści/profesjonaliści smile.gif
Dzięki by_ikar za odpowiedź smile.gif
marcio
U mnie to wyglada tak:
http://code.google.com/p/form-builider/sou...braries/Acl.php
http://code.google.com/p/form-builider/sou...ers/Acl/ini.php
http://code.google.com/p/form-builider/sou...rfaces/IAcl.php

Calosc integruje sie z autoryzacja uzytkownika i klasa User ktora odpowiada za przechowywanie informacji na temat uzytkownika i ogolnie mozna sobie zmieniac ladowanie ustawien acl'a
by_ikar
Cytat
No cóż..., czyli tyle rozwiązań ilu programistów. Ja to trochę inaczej sobie nabazgrałem. Użytkownikowi przypisuję grupę, a grupie role. Grupę użytkownika (jej id) przechowuję w klasie UserProfile, a potem:


Tak, rozwiązań jest wiele, ja swoje zapożyczyłem z symfony 2, a dokładnie to z FOSUserBundle, chodź nie dokładnie takie jakie tam jest, ja raczej tylko podział obiektów zapożyczyłem resztę jakoś sam wystukałem.

I raczej nie używam w ten sposób kontroli dostępu:

  1. $sse->isAllowed('www/admin/projects/add)


Bo musiałbym się bawić nieźle z tymi adresami, a już nie mówię co by było gdybym sobie ten adres zmienił w routerze.. A co z linami które mają różne parametry, np: www/admin/projects/add/25 ? wink.gif Wtedy do poprawki wiele innych rzeczy. U siebie ustawiam to albo na cały moduł (kontroler), albo na konkretną akcję. A nazwy modułów/akcji pobieram z routera. Więc bez względu na to jaki będzie ostatecznie link, liczy się nazwa modułu/akcji, która nie koniecznie jest zamieszczona w adresie.
404
Właśnie zastanawiam się jak to rozwiązać. Np. lista użytkowników zawiera (przykładowo) użytkowników zarejestrowanych (bez aktywnego konta), użytkowników (z aktywnym kontem), użytkowników zbanowanych. Teraz chciałbym żeby np. grupa: 'administratorzy' miała dostęp do wszystkich użytkowników, 'użytkownicy' miała dostęp do wszystkich poza użytkownikami, którzy nie aktywowali konta itd.Chciałbym to zrobić jak najbardziej uniwersalnie, ale wygląda na to, że bez stałych zdefiniowanych "na sztywno" w kodzie się nie obędzie.
Cytat
ustawiam to albo na cały moduł (kontroler), albo na konkretną akcję. A nazwy modułów/akcji pobieram z routera. Więc bez względu na to jaki będzie ostatecznie link, liczy się nazwa modułu/akcji, która nie koniecznie jest zamieszczona w adresie.

Byłbyś tak uprzejmy i podał jakiś przykład, bo nie za bardzo mogę to sobie wyobrazić? smile.gif
by_ikar
Całości ci nie pokaże, bo bym musiał się sporo przy tym naprodukować żeby to opisać.. Generalnie musiałbyś mieć jedną klasę która by sprawdzała uprawnienia: jeżeli niezalogowany, przekierować na stronę logowania, jeżeli po zalogowaniu nadal ma nieodpowiednie uprawnienia poinformować odpowiednim komunikatem. U mnie to jest klasa Authentication, która zarówno autoryzuje użytkownika login/logout jak i w metodach prywatnych sprawdza użytkownika, co określony czas regeneruje sesje i aktualizuje "ostatnią wizytę" użytkownika w bazie danych. Jeżeli znajdę trochę więcej czasu, to mogę spróbować wrzucić te klasy, i je opisać. Tyle że to nie są jakieś osobne klasy, które bez problemu dołączyć do jakiegoś innego systemu, bo nie miałem takiego zamiaru tworząc je. Tak też może być ciężko "skopiować" moje rozwiązanie. Najbardziej uniwersalna z tego wszystkiego jest klasa użytkownika, która z podstawowymi danymi jest tworzona jako pierwsza, zaraz za nią inicjowana jest klasa Authentication, która na podstawie wcześniej inicjowanej klasy User, sprawdza kto jakie ma uprawnienia. A całość inicjuje tak:

  1. if(Config::has('framework.default_database') && Config::has('framework.session') && Config::has('framework.users'))
  2. {
  3. $this->container->setService('user.manager', new UserManager($this->container->getService('database')));
  4. $this->container->setService('user', new User());
  5. $this->container->setService('user.auth', new Authentication($this->container));
  6. $this->container->setService('group.manager', new GroupManager($this->container->getService('database')));
  7. }


A klasa użytkownika, bo w sumie jest najbardziej uniwersalna wygląda tak: https://gist.github.com/1647691 u siebie mam podział na podstawowe pola, oraz pola dodatkowe, takie które można przykładowo z poziomu panelu administratora sobie stworzyć w bazie danych wink.gif większość to są same setery/getery więc za bardzo nie ma co opisywać. Jedynie hasRole, coś tam bardziej skomplikowanego robi.

Więc inicjując klasę User, tworzę "gościa". Na tej podstawie mogę sprawdzić poprzez isUser czy faktycznie jest użytkownikiem, a następnie sprawdzić jego uprawnienia.

  1. if($this->user->isUser())
  2. {
  3. if(false === $this->user->hasRole($role))
  4. {
  5. throw new AccessDeniedException();
  6. }
  7. } else
  8. {
  9. $this->session->set('_user_redirect_url', $this->request->getUri());
  10.  
  11. return new RedirectResponse(Config::get('framework.users.login_url', '/login'));
  12. }


Dodatkowo w przypadku kiedy nie jest użytkownikiem, zapisuje w sesji adres na który ma wrócić po zalogowaniu, a następnie przekierowuje na stronę logowania.
404
Dzięki bardzo za tak wyczerpującą odpowiedź! Sory, że tak długo nie odpowiadałem, ale powiedzmy, że nie mogłem się zebrać.

Cytat
Jeżeli znajdę trochę więcej czasu, to mogę spróbować wrzucić te klasy, i je opisać.

Dzięki, ale nie rób sobie kłopotu. Ostatnio chyba się trochę rozleniwiłem i zapomniałem czym jest programowanie. Napisanie takie prostego systemu to nie jest jakieś bardzo trudne. Wymaga to trochę czasu i myślenia, ale da się to zrobić.

Także dzięki jeszcze raz za pomoc!
Pozdrawiam! smile.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.