Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: User_Authorization (ACL)
Forum PHP.pl > Forum > PHP
Black-Berry
Napisałem klasę autoryzacji użytkownikó. Reguła jest taka że powinna ona pozwalać na:
--- dodawanie ról
--- dodawanie zasobów
--- dzielenie zasobów na akcje
--- zasoby mogą być dziedziczone w linii prostej
--- role mogą dziedziczyć po sobie również w linii prostej

Narobiłem się przy tym jak wół dlatego bardzo proszę o pomoc w testowaniu. Klasa zawiera funkcję drop() która wyświetla całą tabelę. Powinno pomóc. Dla wytrwałych proponuję w zamian działającą klasę. Na pewno się przyda jeśli nie teraz to może w przyszłości smile.gif

  1. //authorization
  2. $auth->addRole('guest');
  3. $auth->addRole('user', 'guest'); // user dziedziczy po guest
  4. $auth->addRole('moderator', 'user'); // moderator dziedziczy po user
  5. $auth->addRole('moderator2', 'user');
  6. $auth->addRole('administrator', 'moderator');
  7. //-----------------
  8. $auth->addResource('article', array('view', 'edit', 'delete')); //nowy zasób artykuł z 3 akcjami view edit i delete
  9. $auth->addResource('backend', array('view', 'edit', 'delete'));
  10. $auth->addResource('structure#1', array('view', 'edit', 'delete'), 'backend');
  11. $auth->addResource('structure#2', array('view', 'edit', 'delete'), 'structure#1'); // struktura#2 dziedziczy po strukturze#1
  12. $auth->addResource('structure#3', array('view', 'edit', 'delete'), 'structure#1');
  13. $auth->addResource('structure#4', array('view', 'edit', 'delete'), 'structure#2');
  14. $auth->addResource('structure#5', array('view', 'edit', 'delete'), 'structure#2');
  15. //-----------------
  16. $auth->allow('administrator'); // ten zapis oznacza ze admin ma prawa do wszstkiego
  17. $auth->allow('moderator', 'backend'); // moderator ma prawo do wszystkiego w backend
  18. $auth->allow('moderator', 'structure#5', array('edit', 'view')); // moderator ma prawo edytowac i edytowac strukture#5
  19. $auth->deny('moderator', 'structure#5', 'edit');
  20. $auth->allow('moderator2', 'structure#2', 'delete');
  21. $auth->deny('moderator', 'backend');
  22. $auth->deny('administrator', 'structure#2', 'delete');



  1. <?php
  2. class User_Authorization
  3. {
  4. private $roles = array();
  5. private $resources = array();
  6. private $acl = array();
  7.  
  8. public function addRole($name, $parent = null)
  9. {
  10. $this->roles[$name] = array('name' => $name, 'parent' => $parent);
  11. }
  12.  
  13. public function addResource($name, $actions = array(), $parent = null)
  14. {
  15. $this->resources[$name] = array('name' => $name, 'actions' => $actions, 'parent' => $parent);
  16. }
  17.  
  18. public function allow($role, $resource = null, $actions = null)
  19. {
  20. $this->acl[] = array('access' => true, 'role' => $role, 'resource' => $resource, 'actions' => $actions);
  21. }
  22.  
  23. public function deny($role, $resource = null, $actions = null)
  24. {
  25. $this->acl[] = array('access' => false, 'role' => $role, 'resource' => $resource, 'actions' => $actions);
  26. }
  27.  
  28. private function _getRoleBloodline($role)
  29. {
  30. $i = 0;
  31. $bloodline = array($this->roles[$role]['name']=>array('name' => $this->roles[$role]['name'], 'level' => $i++));
  32. while ($parent = $this->roles[$role]['parent']) {
  33. foreach ($this->roles as $r) {
  34. if ($r['name'] == $parent) {
  35. $bloodline[$r['name']] = array('name'=>$r['name'], 'level'=>$i++);
  36. $role = $r['name'];
  37. }
  38. }
  39. if (in_array($this->roles[$role]['parent'], $bloodline) || !$this->roles[$parent]) {
  40. break;
  41. }
  42. }
  43. return $bloodline;
  44. }
  45.  
  46. private function _getResourceBloodline($resource)
  47. {
  48. $i = 0;
  49. $bloodline = array($this->resources[$resource]['name'] => array('name' => $this->resources[$resource]['name'], 'level' => $i++));
  50. while ($parent = $this->resources[$resource]['parent']) {
  51. foreach ($this->resources as $r) {
  52. if ($r['name'] == $parent) {
  53. $bloodline[$r['name']] = array('name'=>$r['name'], 'level'=>$i++);
  54. $resource = $r['name'];
  55. }
  56. }
  57. if (in_array($this->resources[$resource]['parent'], $bloodline) || !$this->resources[$parent]) {
  58. break;
  59. }
  60. }
  61. return $bloodline;
  62. }
  63.  
  64. public function isAllowed($role, $resource, $action = null)
  65. {
  66. $roleBloodline = $this->_getRoleBloodline($role);
  67. $resourceBloodline = $this->_getResourceBloodline($resource);
  68. $isAllowed = false;
  69. $isAllowedPoints = 100;
  70. if ($action === null) {
  71. $isAllowed = false;
  72. foreach ($this->resources[$resource]['actions'] as $a) {
  73. if (!$isAllowed = $this->isAllowed($role, $resource, $a)) {
  74. break;
  75. }
  76. }
  77. } else {
  78. foreach ($this->acl as $ac) {
  79. if ($roleBloodline[$ac['role']] && $resourceBloodline[$ac['resource']]) {
  80. if ($isAllowedPoints >= $roleBloodline[$ac['role']]['level'] + $resourceBloodline[$ac['resource']]['level'] / 100) {
  81. if ($ac['access']) {
  82. if (is_array($ac['actions']) && in_array($action, $ac['actions']) || $action == $ac['actions'] || !$ac['actions']) {
  83. $isAllowed = true;
  84. }
  85. } else {
  86. if (is_array($ac['actions']) && in_array($action, $ac['actions']) || $action == $ac['actions'] || !$ac['actions']) {
  87. $isAllowed = false;
  88. }
  89. }
  90. $isAllowedPoints = $roleBloodline[$ac['role']]['level'] + $resourceBloodline[$ac['resource']]['level'] / 100;
  91. }
  92. } else if ($roleBloodline[$ac['role']] && !$ac['resource']) {
  93. if ($ac['access']) {
  94. $isAllowed = true;
  95. } else {
  96. $isAllowed = false;
  97. }
  98. }
  99. }
  100. }
  101. return $isAllowed;
  102. }
  103.  
  104.  
  105. }
  106. ?>


to się nie zmieściło do posta....
  1. public function drop()
  2. {
  3. echo "<style type=\"text/css\">\n";
  4. echo "\t#userAuthorizationTableTitle {float:left; color:#516c7d; border:0px dashed #666; font-size:12px; font-family:tahoma; padding:0px 10px 0px 10px; background-color:#fcc; margin:0px; border:1px dashed #666; border-bottom:0px; margin-top:10px;}\n";
  5. echo "\t#userAuthorizationTable {border-collapse:collapse; clear:both; border-top:1px dashed #666; border-left:1px dashed #666; font-size:12px; background-color:#fcc; font-family:tahoma; color:#666; width:100%; margin-bottom:0px;}\n";
  6. echo "\t#userAuthorizationTable tr{border-collapse:collapse; border:0px dashed #666; font-size:12px; font-family:tahoma; color:#666;}\n";
  7. echo "\t#userAuthorizationTable tr th{padding:0px; border-collapse:collapse; vertical-align:top; background-repeat:no-repeat; padding-left:20px; border-right:1px dashed #666; border-bottom:1px dashed #666; text-align:left; color:#516c7d; background-color:#fbbbbb}\n";
  8. echo "\t#userAuthorizationTable tr td{border-collapse:collapse; border-right:1px dashed #666; border-bottom:1px dashed #666; color:#666; padding-left:5px;}\n";
  9. echo "</style>\n";
  10. echo '<h1 id="userAuthorizationTableTitle">User authorization table </h1>';
  11. echo '<table id="userAuthorizationTable" cellspacing="0" cellpadding="0">';
  12. echo '<tr>';
  13. $width = 100 / (count($this->roles) + 1);
  14. echo '<td width="'.$width.'%"></td>';
  15. foreach ($this->roles as $role) {
  16. echo '<th style="background-image:url(\'edc_application/System/Images/UserIcon.gif\'); padding-left:15px;" width="'.$width.'%">';
  17. echo $role['name'];
  18. if ($role['parent']) echo ' (' . $role['parent'] . ')';
  19. echo '</th>';
  20. }
  21. echo '</tr>';
  22. foreach ($this->resources as $resource) {
  23. echo '<tr>';
  24. echo '<th style="background-image:url(\'edc_application/System/Images/ResourceIcon.gif\')">';
  25. echo $resource['name'];
  26. if ($resource['parent']) echo ' (' . $resource['parent'] . ')';
  27. echo '</th>';
  28. foreach ($this->roles as $role) {
  29. echo '<td>';
  30. $c = 0;
  31. foreach ($resource['actions'] as $action) {
  32. if ($this->isAllowed($role['name'], $resource['name'], $action)) {
  33. if ($c++) echo ', ';
  34. echo $action;
  35. }
  36. }
  37. if ($this->isAllowed($role['name'], $resource['name'])) {
  38. echo ' IS_ALLOWED';
  39. }
  40. echo '</td>';
  41. }
  42. echo '</tr>';
  43. }
  44. echo '</table>';
  45. }
everth
Eee, czy ty czasem nie przepisujesz Zend_Acl?

@DOWN:
Jeśli robi to dla praktyki to nic mi do tego. Jeśli jednak chce to użyć gdzieś produkcyjnie to raczej przepisywanie się nie opłaca - ta sama funkcjonalność a prawdopodobieństwo popełnienia błędu znacznie większe.
Co do lekkości to sprawdziłem trunka - samo Acl z klasami pomocniczymi to obecnie ~15kb, a prawdopodobnie znacznie stabilniejsze (czy lepiej zaprojektowane, sprawa dyskusyjna) - przecież nie musi całego ZFa pakować w aplikację.
Dzięki za PHPUnit - też się przyda.
wookieb
Cytat(everth @ 11.08.2010, 01:57:48 ) *
Eee, czy ty czasem nie przepisujesz Zend_Acl?

Tylko, że jest znacznie lżejesz.

Co do testowania zainteresuj się testami jednostkowymi (phpunit), bo to do tego służy.
Black-Berry
Zend_Acl nie pozwala na dziedziczenie zasobów chyba że coś przeoczyłem. Mam swój framework i nastawiłem się już że piszę go w całości od podstaw dlatego wolałbym nie korzystać z Zenda. Czy ktoś miałby chwilę to przetestować? Ta funkcja drop() wyświetla od razu tabelkę ról i uprawnień więc nie powinno zająć to dużo czasu. Wystarczy przekleić.
jang
Cytat(Black-Berry @ 11.08.2010, 09:18:59 ) *
Wystarczy przekleić.
Zgodnie z życzeniem przekleiłem winksmiley.jpg
Moim zdaniem działa smile.gif , dziedziczenie również (trochę od siebie dodałem, wywaliłem ... , zgodnie z tym co zrobiłem zawartość tabeli się zmieniała, więc działa)
Cytat(Black-Berry @ 11.08.2010, 09:18:59 ) *
Ta funkcja drop() wyświetla od razu tabelkę...

Zastanawia mnie tylko to "IS_ALLOWED" (kodu nie studiowałem) , czy to jest info o tym, że wszystko co jest możliwe zostało udostępnione temu użytkownikowi ? (bo tylko dla administratora dla article wyświetla się "jest dozwolone" <- dla przykładu który Ty podałeś)
Dla pełnej jasności co wogóle jest dostępne i co danemu użytkownikowi zostało odebrane
  1. $auth->deny('administrator', 'structure#2', 'delete');
to dołożyłbym np. na czerwono w tabelce to powyższe "delete"
Black-Berry
IS_ALLOWED w tabelce oznacza, że wszystkie akcje są dozwolone. Jest to test dla opcji bez podawania akcji czyli np mozna stosowac klasę tak
  1. $acl->allow('user', 'article');

i odpytać:
  1. $acl->isAllowed('user', 'article')

Dzięki temu można stosować klasę w mniejszych projektach bez podziału na akcje.

Dalsze testy wskazane smile.gif Na pewno muszą być jakieś bugi 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.