Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Struktura uprawnień w CMS'ie
Forum PHP.pl > Forum > PHP > Pro > Archiwum Pro
matid
Witam,

Chciałbym się dowiedzieć, jak rozwiązalibyście problem struktury uprawnień w CMS'ie. Potrzebuję Waszych opini, gdyż sam piszę takiego CMS'a (jak chyba większość osób, które znają lepiej php tongue.gif).
Jak rozwiązać przydzielanie uprawnień do użytkowników? Tzn. chcę np. nadawać uprawnienia w stylu dodawanie wiadomości, dodawanie artykułów (z możliwością nadawania uprawnień do zapisu, odczytu, lub edycji dla poszczególnych kategorii). Jak rozwiązać uprawnienia grup i na jakiej zasadzie oprzeć ich dziedziczenie ?
Proszę o Wasze opinie, napewno będą one pomocne.
jaco
To jest naprawde twardy orzech. To musi byc jak najbardziej dynamiczne, system nie musi miec newsow a musi wiedziec jakie uprawnienia mozna przydzielic userowi dla danego modulu.

Zastnanawialem sie nad definiowaniem rodzajow uprawnien w samym module i ich przporzatkowywanie do danych operacji w owym module - system moglby je odczytywac i na ich podstawie przydzielac uprawnienia (ktore definiuje osoba do tego uprawniona)
matid
Dzięki Wam. Narazie wykombinowałem coś takiego:
  1. <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
  2. <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"pl\">
  3. <head>
  4. <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-2\" />
  5. <meta http-equiv=\"Reply-to\" content=\"matid@seishi.net\" />
  6. <link rel=\"stylesheet\" title=\"default\" type=\"text/css\" href=\"style.css\" />
  7. </head>
  8. <body>
  9. <?
  10. require_once(&#092;"adodb/adodb.inc.php\");
  11. $sql = &ADONewConnection('mysql');
  12. $sql->connect(&#092;"localhost\",\"anime\",\"anime\",\"chmod\"); // laczy z baza danych
  13. class user {
  14. function info($id){
  15.  global $sql;
  16.  $users = $sql->execute(&#092;"SELECT id, login FROM user WHERE id = '\" . $id . \"'\");
  17.  $this->id = $users->fields['id'];
  18.  $this->login = $users->fields['login'];
  19. }
  20. function group($id){
  21. global $sql;
  22. $r_1 = $sql->execute(&#092;"SELECT id, nazwa, grupa_nadrzedna FROM grupa WHERE id = '$id'\");
  23. $this->group_data[] = array(&#092;"id\" => $r_1->fields['id'], \"nazwa\" => $r_1->fields['nazwa'], \"grupa_nadrzedna\" => $r_1->fields['grupa_nadrzedna']);
  24. if($r_1->fields['grupa_nadrzedna']!=0){
  25. $this->group($r_1->fields['grupa_nadrzedna']);
  26. }
  27. }
  28. function groups($id){
  29. global $sql;
  30. $r_1 = $sql->execute(&#092;"SELECT id_grupa FROM user_grupa WHERE id_user = '\" . $id . \"'\");
  31. while(!$r_1->EOF){
  32. $r_2 = $sql->execute(&#092;"SELECT id, nazwa, grupa_nadrzedna FROM grupa WHERE id = '\" . $r_1->fields['id_grupa'] . \"'\");
  33. $this->group[] = array(&#092;"id\" => $r_2->fields['id'], \"nazwa\" => $r_2->fields['nazwa'], \"grupa_nadrzedna\" => $r_2->fields['grupa_nadrzedna']);
  34. $r_1->MoveNext();
  35. }
  36. }
  37. function auth($id, $dzial){
  38. global $sql;
  39. $this->groups($id);
  40. for($i=0;$i<count($this->group);$i++){
  41. $this->group($this->group[$i]['id']);
  42. }
  43. $this->group = $this->group_data;
  44. $this->dzial($dzial);
  45. for($ag = 0; $ag<count($this->group); $ag++){
  46.  $r_1 = $sql->execute(&#092;"SELECT id_uprawnienia_zespolu FROM grupa_zespol_uprawnien WHERE id_grupa = '\" . $this->group[$ag]['id'] . \"'\");
  47.  while(!$r_1->EOF){
  48.  $r_2 = $sql->execute(&#092;"SELECT id_uprawnien FROM uprawnienia_zespol WHERE id = '\" . $r_1->fields['id_uprawnienia_zespolu'] . \"'\");
  49.  while(!$r_2->EOF){
  50.  $r_3 = $sql->execute(&#092;"SELECT id, nazwa, liczba FROM uprawnienia WHERE id = '\" . $r_2->fields['id_uprawnien'] . \"'\");
  51.  for($z=0; $z<count($this->dzial['uprawnienia']); $z++){
  52.  if($r_3->fields['id']==$this->dzial['uprawnienia'][$z]){
  53.  $liczba += $r_3->fields['liczba'];
  54.  $result[] = array(&#092;"id\" => $r_3->fields['id'], \"nazwa\" => $r_3->fields['nazwa'], \"odczyt\" => $r_3->fields['liczba'][0], \"zapis\" => $r_3->fields['liczba'][1], \"edycja\" => $r_3->fields['liczba'][2], \"usuwanie\" => $r_3->fields['liczba'][3]);
  55.  }
  56.  }
  57.  $r_2->MoveNext();
  58.  }
  59.  $r_1->MoveNext();
  60.  }
  61. }
  62. if($liczba>1111){
  63. $liczba = 1111;
  64. }
  65. $liczba = $this->zeroFill($liczba,'4');
  66. $liczba = strval($liczba);
  67. $result['perms'] = array(&#092;"odczyt\" => $liczba[0], \"zapis\" => $liczba[1], \"edycja\" => $liczba[2], \"usuwanie\" => $liczba[3]);
  68. return $result;
  69. }
  70. function check($usr_id,$dzial, $upr_id, $what){
  71. $auth = $this->auth($usr_id,$dzial);
  72. for($i=0; $i<count($auth)-1; $i++){
  73. if($auth[$i]['id']==$upr_id){
  74. return $auth[$i][$what];
  75. }
  76. }
  77. return 0;
  78.  
  79. }
  80. function zeroFill($liczba, $ilosc_cyfr) {
  81. $liczba = strval($liczba);
  82. $ile = strlen($liczba);
  83. if($ile < $ilosc_cyfr){
  84. $liczba = strrev($liczba);
  85. $liczba *= pow(10,$ilosc_cyfr-$ile);
  86. $liczba = strrev($liczba);
  87. }
  88. return $liczba;
  89. }
  90. function dzial($id){
  91. global $sql;
  92. $r_1 = $sql->execute(&#092;"SELECT id, nazwa FROM dzialy_strony WHERE id = '$id'\");
  93. $r_2 = $sql->execute(&#092;"SELECT id_uprawnienia FROM dzialy_strony_uprawnienia WHERE id_dzialy_strony
     
  94.  '$id'\");
  95. while(!$r_2->EOF){
  96. $auth[] = $r_2->fields['id_uprawnienia'];
  97. $r_2->MoveNext();
  98. }
  99. $return = array(\"id\" => $r_1->fields['id'], \"nazwa\" => $r_1->fields['nazwa'], \"uprawnienia\" => $auth);
  100. $this->dzial = $return;
  101. return $return;
  102. }
  103. }
  104. $user = new user;
  105. $user->info(1); // pobiera dane użytkownika o id == 1
  106. $dzial = 1; // numer dzialu
  107. $auth = $user->auth($user->id,$dzial);
  108. echo \"Uprawnienia użytkownika: <br /><hr noshade size=1 color=black />\";
  109. echo \"Dział: \" . $user->dzial['nazwa'] . \"<br />\";
  110. for($i=0; $i<count($auth)-1; $i++){
  111. echo \"ID: \" . $auth[$i]['id'] . \"<br />\";
  112. echo \"Nazwa: \" . $auth[$i]['nazwa'] . \"<br />\";
  113. echo \"Uprawnienia:<ul>\";
  114. echo \"<li>Odczyt: \" . $auth[$i]['odczyt'] . \"</li>\";
  115. echo \"<li>Zapis: \" . $auth[$i]['zapis'] . \"</li>\";
  116. echo \"<li>Edycja: \" . $auth[$i]['edycja'] . \"</li>\";
  117. echo \"<li>Usuwanie: \" . $auth[$i]['usuwanie'] . \"</li>\";
  118. echo \"</ul>\";
  119. echo \"<hr noshade size=1 color=black />\";
  120. }
  121. echo \"Uprawnienia końcowe: <br /><ul>\";
  122. echo \"<li>Odczyt: \" . $auth['perms']['odczyt'] . \"</li>\";
  123. echo \"<li>Zapis: \" . $auth['perms']['zapis'] . \"</li>\";
  124. echo \"<li>Edycja: \" . $auth['perms']['edycja'] . \"</li>\";
  125. echo \"<li>Usuwanie: \" . $auth['perms']['usuwanie'] . \"</li></ul>\";
  126.  
  127. echo $user->check($user->id,$dzial,3,\"edycja\"); // sprawdza czy uzytkownik ma upranienia do edycji tego, co opisuje w bazie uprawn
  128. enie o id = 3
  129. ?>
  130. </body>
  131. </html>

i baza danych:
  1. # MySQL-Front Dump 2.5
  2.  
  3. CREATE TABLE IF NOT EXISTS dzialy_strony (
  4. id tinyint(3) UNSIGNED DEFAULT '0' ,
  5. nazwa varchar(10) DEFAULT '0'
  6. );
  7.  
  8. INSERT
  9. INTO dzialy_strony VALUES("1", "Newsy");
  10. INSERT
  11. INTO dzialy_strony VALUES("2", "Artykuły");
  12.  
  13. CREATE TABLE IF NOT EXISTS dzialy_strony_uprawnienia (
  14. id_dzialy_strony tinyint(3) UNSIGNED DEFAULT '0' ,
  15. id_uprawnienia tinyint(3) UNSIGNED DEFAULT '0'
  16. );
  17.  
  18. INSERT
  19. INTO dzialy_strony_uprawnienia VALUES("1", "1");
  20. INSERT
  21. INTO dzialy_strony_uprawnienia VALUES("1", "2");
  22. INSERT
  23. INTO dzialy_strony_uprawnienia VALUES("1", "3");
  24. INSERT
  25. INTO dzialy_strony_uprawnienia VALUES("1", "4");
  26. INSERT
  27. INTO dzialy_strony_uprawnienia VALUES("2", "5");
  28.  
  29. CREATE TABLE IF NOT EXISTS grupa (
  30. id tinyint(3) UNSIGNED DEFAULT '0' ,
  31. nazwa varchar(50) DEFAULT '0' ,
  32. grupa_nadrzedna tinyint(3) UNSIGNED DEFAULT '0'
  33. );
  34.  
  35. INSERT
  36. INTO grupa VALUES("1", "Użytkownicy", "0");
  37. INSERT
  38. INTO grupa VALUES("2", "Administratorzy", "1");
  39. INSERT
  40. INTO grupa VALUES("0", "Goście", "0");
  41. INSERT
  42. INTO grupa VALUES("3", "Redaktorzy", "1");
  43.  
  44. CREATE TABLE IF NOT EXISTS grupa_zespol_uprawnien (
  45. id_grupa tinyint(3) DEFAULT '0' ,
  46. id_uprawnienia_zespolu tinyint(3) UNSIGNED DEFAULT '0'
  47. );
  48.  
  49. INSERT
  50. INTO grupa_zespol_uprawnien VALUES("1", "1");
  51. INSERT
  52. INTO grupa_zespol_uprawnien VALUES("2", "2");
  53. INSERT
  54. INTO grupa_zespol_uprawnien VALUES("1", "3");
  55. INSERT
  56. INTO grupa_zespol_uprawnien VALUES("3", "4");
  57. INSERT
  58. INTO grupa_zespol_uprawnien VALUES("1", "5");
  59.  
  60. CREATE TABLE IF NOT EXISTS uprawnienia (
  61. id tinyint(3) UNSIGNED DEFAULT '0' ,
  62. nazwa varchar(50) DEFAULT '0' ,
  63. liczba int(4) UNSIGNED ZEROFILL DEFAULT '0000'
  64. );
  65.  
  66. INSERT
  67. INTO uprawnienia VALUES("2", "Administracja newsami", "0011");
  68. INSERT
  69. INTO uprawnienia VALUES("1", "Przeglądanie newsów", "1000");
  70. INSERT
  71. INTO uprawnienia VALUES("3", "Komentowanie newsów", "1100");
  72. INSERT
  73. INTO uprawnienia VALUES("4", "Dodawanie newsów", "0110");
  74. INSERT
  75. INTO uprawnienia VALUES("5", "Przeglądanie artykułów", "1000");
  76.  
  77. CREATE TABLE IF NOT EXISTS uprawnienia_zespol (
  78. id tinyint(3) UNSIGNED DEFAULT '0' ,
  79. nazwa varchar(50) DEFAULT '0' ,
  80. id_uprawnien tinyint(3) UNSIGNED DEFAULT '0'
  81. );
  82.  
  83. INSERT
  84. INTO uprawnienia_zespol VALUES("1", "Administracja newsami", "1");
  85. INSERT
  86. INTO uprawnienia_zespol VALUES("2", "Przegladanie newsów", "2");
  87. INSERT
  88. INTO uprawnienia_zespol VALUES("3", "Komentowanie newsów", "3");
  89. INSERT
  90. INTO uprawnienia_zespol VALUES("4", "Dodawanie newsów", "4");
  91. INSERT
  92. INTO uprawnienia_zespol VALUES("5", "Przeglądanie artykułów", "5");
  93.  
  94. CREATE TABLE IF NOT EXISTS user (
  95. id tinyint(3) UNSIGNED NOT NULL DEFAULT '0' ,
  96. login varchar(10) DEFAULT '0' ,
  97. PRIMARY KEY (id)
  98. );
  99.  
  100. INSERT
  101. INTO user VALUES("1", "matid");
  102.  
  103. CREATE TABLE IF NOT EXISTS user_grupa (
  104. id_user tinyint(3) UNSIGNED DEFAULT '0' ,
  105. id_grupa tinyint(3) UNSIGNED DEFAULT '0'
  106. );
  107.  
  108. INSERT
  109. INTO user_grupa VALUES("1", "3");


Skrypt korzysta z ADODB i bez tego nie ruszy smile.gif

Proszę o opinie.
jaco
Jezeli dobrze do konca zrozumialem to nic tutaj nie wnosi albowiem nie chodzi o news czy artykul a dowolny modul i dowolna akcje - to nie musi byc dodawanie czy edycja - chce zaistalowac modul i miec mozliwosc nadania uprawnien userowi, ktore udostepnia mi dany modul - to rozwiazanie napenwo jest dobre ale dla zdefiniowanego systemu.
hawk
Uhmn, ten wielki kod tutaj nic nie daje bo kwestia nie jest w implementacji tylko w projekcie. Typowym grzechem w php jest przeskoczenia na zasadzie hurra do kodowania i mówienie "patrzcie, to jest mój projekt systemu". Programiści php przejawiają zadziwiającą, masochistyczną ochotę to zaglądania w (cudzy co gorsza) kod, który robi im za projekt, analizę, a nawet specyfikację wymagań smile.gif Może przydałby się artykuł o UML...

Ale do rzeczy. Dobry system uprawnień powinien mieć definiowalne, zagnieżdżalne grupy. A nie na sztywno userzy, moderatorzy, admini... koniec. Bez sensu, nieelastyczne i bardziej złożone.

Dobry system uprawnień nie powinien mieć wbudowanych na sztywno uprawnień typu "może dodawać artykuły", "może edytować artykuły"... Robi się tego potwornie dużo, a i tak wszystkiego sie nie pokryje.

Dobry system uprawnień powinien IMHO mieć tylko jeden rodzaj uprawnień: <user> może/nie może <czynność>. Gdzie <user> to jest nasz user albo grupa, <czynność> to "tworzenie postów", "usuwanie postów", itd. Najprościej to zrobić gdy "tworzenie postów" jest po prostu obiektem. I tak dochodzę do tego do czego zawsze dochodzę, czyli do MVC, bo taki obiekt to wypisz wymaluj akcja :wink: .
matid
W tym kodzie nie ma z góry zdefiniowanych grup. Wszystko można zmienić, ale narazie tylko z poziomu mysql, bo nie mam jeszcze konsoli admina napisanej. Grupy, użytkownicy i uprawnienia są nadane przypadkowo. Chodziło mi o waszą opinię na temat takiego rozwiązania (w tym wypadku przede wszystkich dziedziczenia uprawnień)
jaco
Mi sie owe rozwiazanie nie podoba, co wiecej lepiej byloby abys opisal sposob dzialania a nie wklejal caly kod wraz ze struktura tabel smile.gif

Tutaj raczej wazniejsze jest rozwiazanie, realizacja to juz najmniejsy problem.
Sh4dow
Ja osobiscie mam podobny stosunek do hawk'a. Nie mozna na sztywno wpisywacdowolonych czynnosci.
Duzo wygodniej bedzie zbudowac tablice uprawnien. Uprawnienia, jesli juz chcesz dzielic.to podziel sobie uprawnienie na poziomy. Powiedzmy liczby od 1-4 gdzie 1 do podstawowe dostepy dla usera/grupy a 4 to pelna administracja. Tablice w bazie mozesz zrobic tak user_id|uprawnienie|modul.
Tablica chyba jest w miare jazno opisana. Mozna do tego zrobic funkje/metode, ktora sprawdza uprawnienia w danym module.
A w module administracyjnym bedziesz musial pamietac piszac zeby podzielic administracje na takie bloki. Im wiekszy poziom usera/grupt tym wiecej tych blokow pojawia mu sie.
Zamiast pisac juz gotowe skrypty, przeanalizuj to i rozryzuj sobie zebys mogl sie pozniej, podczas pisania skryptu, mial na czym opierac.
Życze powodzenia w pisaniu
halfik
Cytat
Może przydałby się artykuł o UML...

A wiesz, że to nie głupi pomysł? winksmiley.jpg Napiszesz ? winksmiley.jpg
e-Gandalf
Cytat
Uhmn, ten wielki kod tutaj nic nie daje bo kwestia nie jest w implementacji tylko w projekcie. Typowym grzechem w php jest przeskoczenia na zasadzie hurra do kodowania i mówienie "patrzcie, to jest mój projekt systemu".


Kazdy jezyk typu user-friendly boryka sie z takimi problemami smile.gif

Od siebie:

Zagniezdzane grupy, elastyczne zestawy uprawnien podzielone na grupy (wiem, trudno to opisac) i nakladanie sie uprawnien - a'la Unix i dwustronne uprawnienia - a'la Windows

definiuje dowolne grupy - ble, ble1, ble2 - z zagniezdzeniami, definiuje dowolne grupy uprawnien - jadro, news, forum - z zagniezdzeniami, kazdy uzytkownik moze miec uprawnienia in plus albo in minus. I potem jade po kolej:
1) pobieram grupy dla usera, jade od gory biorac uprawniania grupy na tablice uprawnien usera, jesli nastepna grupa nadpisuje cos, to nadpisuje to w tablicy, na koncu nakladam na to uprawnienia solowe uzytkownika i mam tablice uprawnien.

Wiem, ze brzmi trudno, ale realizacja nie jest juz tak skomplikowana. Zaleta tego modelu (sprawdzone winksmiley.jpg) jest wygoda w dodawaniu grup uprawnien modulow. Jesli tworzymy MMCMS (Massive Multiplayer CMS winksmiley.jpg) ktory ma budowe Linuxa - jadro abstrakcyjne i setki mozliwych modulow do zaladowania to kazdy z tych modulow podczas instalacji moze zglaszac swoje grupy uprawnien (oznaczone sygnatura modulu - u mnie typu type.author.owner.name) dzieki temu w jadrze nie ma czegos takiego jak kontrola uprawnien do forum czy newsow czy innych galerii, a w momencie instalacji lub wlaczenia modulu dla serwisu te uprawnienia zostaja dodane do zestawu.
Bora
a mi dziś wpadł do głowy prosty a zarazem bardzo elastyczny pomysł.

[sql:1:b9b96a4b2f]CREATE TABLE `cms_acces` (
`id` smallint(5) unsigned NOT NULL auto_increment,
`module` varchar(30) NOT NULL default '0',
`user_group` smallint(6) NOT NULL default '0',
`status` tinyint(4) NOT NULL default '0',
`auth_admin` tinyint(2) NOT NULL default '0',
`auth_rights` text NOT NULL,
PRIMARY KEY (`id`),
KEY `cat_id` (`module`)
) ENGINE=MyISAM DEFAULT CHARSET=latin2 AUTO_INCREMENT=19 ;[/sql:1:b9b96a4b2f]

status zaaiwra info czy jest moduł jest włączony.
`auth_admin` to sa pełne uprawniania, natomiast w `auth_rights` znajduje sie zserializowana tablica z uprawnainiami.
np:
[php:1:b9b96a4b2f]<?php
$auth['auth_view']='1';
$auth['auth_add']='0';
$auth['auth_reply']='1';
$auth['auth_edit']='0';
$auth['auth_delete']='0';
var_dump($auth);
foreach ($auth as $key=>$var){
echo $key.'-'.$var.'<br>';
}
var_dump(serialize($auth));
?>[/php:1:b9b96a4b2f]
pozwala to na dostosowywanie uprawnień do każdego modułu indywidualnie.
co o tym sądzicie??
cichy
Bora: nad IDENTYCZNYM rozwiązaniem pracuje od 2 tygodni... tylko że od półtora tygodnia mi sie nie chce nic w tym kierunku pisać..
ale dzieki temu uprawnienia sa dodawane dynamicznie razem z modulem... i każdy moduł moze mieć włąsne uprawnienia biggrin.gif

Problem pojawia sie dopiero gdy trzeba te uprawnienia sprawdzac ... np przy generowaniu menu tongue.gif

Pozdro
Bora
oradziłę soebie z tym.
Każdy moduł ma baze gdzie znajduje sie jego stan.
Natomiast w w porównaniu z poprzednim rozwiązaniem zamiast auth_admin jest auth_view czyli czy user ma prawo ogl.ądać ten moduł. reszta znajduje sie już w tablicy zserializowanej.
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.