PHP MySQL Zend-ACL - Графически отображать ACL: - PullRequest
3 голосов
/ 22 декабря 2010

У меня есть одна таблица БД MySQL, подобная следующей, таблица ресурсов :

+----+-----------+------------+
| id | name      | type       |
+----+-----------+------------+
| 1  | guest     | user       |
| 2  | member    | user       |
| 3  | moderator | user       |
| 4  | owner     | user       |
| 5  | admin     | user       |
| 6  | index     | controller |
+----+-----------+------------+

На следующую таблицу, таблица правил :

+----+---------+------+-------------+----------------------+
| id | user_id | rule | resource_id | extras               |
+----+---------+------+-------------+----------------------+
| 1  | 2       | 3    | 1           | null                 |
| 2  | 3       | 3    | 2           | null                 |
| 3  | 4       | 3    | 3           | null                 |
| 4  | 5       | 3    | 4           | null                 |
| 5  | 6       | 1    | 1           | index,login,register |
| 6  | 6       | 2    | 2           | login,register       |
| 7  | 6       | 1    | 2           | logout               |
+----+---------+------+-------------+----------------------+

Хорошо, извините за длину, но я пытаюсь дать полное представление о том, что я пытаюсь сделать. Таким образом, как это работает, роль (он же пользователь) может быть предоставлена ​​ (правило: 1) доступ к контроллеру, роль может наследовать (правило: 3) доступ из другой роли или роли и отказано (правило: 2) доступ к контроллеру. (A пользователь - это ресурс, а контроллер - это ресурс)

Доступ к действиям предоставляется / запрещается с помощью столбца «Дополнительно».

Это все работает, это не проблема с настройкой ACL в Zend.


Что я сейчас пытаюсь сделать, это показать отношения; для этого мне нужно найти самый низкий уровень, которому роли предоставляется доступ к остановке контроллера, если он был явно удален. Я планирую перечислить роли. Когда я нажимаю на роль, я хочу, чтобы она показывала все контроллеры, к которым у этой роли есть доступ. Затем щелчок по контроллеру показывает действия, которые разрешено выполнять роли.

Таким образом, в приведенном выше примере гостю разрешено просматривать действие index контроллера индекса вместе с действием login. Член наследует тот же доступ, но затем ему отказывают в доступе к действию входа в систему и действию регистрации. Модератор наследует правила участника.

Так что, если бы я выбрал роль модератора. Я хочу видеть индекс контроллера в списке. Если я нажимаю на контроллер, он должен показывать разрешенные действия как action: index. (который был первоначально предоставлен гостю, но с тех пор не был отклонен)

Есть ли примеры для этого? Я очевидно работаю с Zend MVC (PHP) и MySQL. Даже простой пример кода персудо будет полезной отправной точкой - это одна из последних частей мозаики, которую я собираю.

P.S. Очевидно, что у меня есть объект ACL - будет ли легче его интегрировать или лучше сделать это самостоятельно через PHP / MySQL?

Цель состоит в том, чтобы показать, к какой роли может получить доступ, что затем позволит мне добавить или отредактировать роль, контроллер и действие в стиле графического интерфейса пользователя (это довольно просто) - в настоящее время я обновляю БД вручную, как я строил сайт.

Ответы [ 2 ]

2 голосов
/ 23 декабря 2010

Ну а после того, как я немного прибегнул к поиску и не смог найти ответ, я немного подумал над этим, и вот решение, которое я придумал (просто полезно для кого-то другого):

Сначала Psuedo:

  1. Показать страницу со списком всех ролей (уровни пользователя) из ACL $acl->getRoles() в качестве ссылки.
  2. Нажмите на ссылку и перезагрузите страницу, передав в качестве параметра роль .
    • Теперь возьмите все контроллеры из ACL $acl->getResources(), проверяя, что ресурс не играет роли (массив, возвращаемый getResources, также будет содержатьРоли) .
    • перебрать каждый контроллер , получить все записи из таблицы rules , в которой идентификатор controller находится в resource_idустановите и взорвите дополнительные функции (действия, разделенные запятыми)
    • Далее выполните цикл для каждого действия , вызывая isAllowed (Iиметь роль, контроллер и действие) . ЕСЛИ найден хотя бы один «разрешен», я окрашиваю контроллер в зеленый цвет (разрешен доступ хотя бы к одному действию в контроллере) , в противном случае его красный (нет доступа кчто-нибудь в этом контроллере) каждый элемент списка можно щелкнуть, чтобы перезагрузить страницу
  3. Теперь, когда контроллер нажимается, я перезагружаю страницу, теперь, при просмотре списка действий, вызывая isAllowed Я создаю список действий для выбранного контроллера, окрашивая действие зеленым или красным на основе результата isAllowed

Ответ сам по себе почти такой же длинный, как ивопрос, но он работает для меня, давая очень четкое представление о том, что может сделать каждая роль.Вот, если это поможет кому-либо:

Теперь для кода:

AdminController:

public function aclAction()
{
    $this->view->content_title = "Access Rules:";

    // Get the ACL - its stored in the session:
    $usersNs = new Zend_Session_Namespace("ZEND_SITE");
    $acl = $usersNs->acl;

    // List all Roles in the ACL:
    $roles = $acl->getRoles();
    // Pass the roles to the view:
    $this->view->roles = $roles;

    // Check if a role has been clicked on:
    $role = this->_getParam('role');
    if(!is_null($role))
    {
        // Pass the role to the view:
        $this->view->role = $role;

        // Get all the resources (controllers) from the ACL, don't add roles:
        $controllers = array();
        foreach ($acl->getResources() as $res)
        {
            if (!in_array($res, $roles))
            {
                $controllers[] = $res;
            }
        }

        // Create a Rules Model:
        $rules = new Model_ACLrules();

        // Store controllers + access:
        $all_controllers = array();

        // Check if the controller has been passed:
        $cont = $this->_getParam('cont');

        // Loop through each controller:
        foreach ($controllers as $controller)
        {
            // Get all actions for the controller:
            // THIS IS THE PART I DON'T LIKE - BUT I SEE NO WAY TO GET
            // THE RULES FROM THE ACL - THERE LOOKS TO BE A METHOD
            // BUT IT IS A PROTECTED METHOD - SO I AM GETTING THE ACTIONS 
            // FROM THE DB, BUT THIS MEANS TWO SQL QUERIES - ONE TO FIND
            // THE RESOURCE FROM THE DB TO GET ITS ID THEN ONE TO FIND
            // ALL THE EXTRAS FOR IT:
            $all_rules = $rules->findAllActions($controller);

            // Store if the role is allowed access somewhere in the controller:
            $allowed = false;

            // Store selected controller actions:
            $cont_actions = array();

            // Loop through all returned row of actions for the resource:
            foreach ($all_rules as $rule)
            {
                // Split the extras field:
                $extras = explode(",", $rule->extras); 

                // Check if the role has access to any of the actions:
                foreach ($extras as $act)
                {
                    // Store matching selected controller:
                    $match = ($cont==$controller)?true:false;

                    // Store the action if we are looking at a resource:
                    if ($match)$temp = array("action"=>$act,"allowed"=>false);

                    // Check if the role is allowed:
                    if ($acl->isAllowed($role,$controller,$act))
                    {
                        // Change the controllers allowed to ture as at least one item is allowed:
                        $allowed = true;

                        // Change the matched controllers action to true:
                        if ($match)$temp = array("action"=>$act,"allowed"=>true);
                    }

                    // Check if the action has already been added if we are looking at a resource:
                    if ($match)
                    {
                        $add = true;
                        // This is done because there could be several rows of extras, for example
                        // login is allowed for guest, then on another row login is denied for member,
                        // this means the login action will be found twice for the resource,
                        // no point in showing login action twice:
                        foreach ($cont_actions as $a)
                        {
                            // Action already in the array, don't add it again:
                            if ($a['action'] == $act) $add = false;
                        }
                        if($add) $cont_actions[] = $temp;
                    }
                }
            }

            // Pass a list of controllers to the view:
            $all_controllers[] = array("controller" => $controller, "allowed" => $allowed);

            // Check if we had a controller:
            if(!is_null($cont))
            {
                // Pass the selected controller to the view:
                $this->view->controller = $cont;

                // Check if this controller in the loop is the controller selected:
                if ($cont == $controller)
                {
                    // Add the controller + actions to the all rules:
                    $this->view->actions = $cont_actions;
                }
            }
        }

        // Pass the full controller list to the view:
        $this->view->controllers = $all_controllers;
    }   
}

Следующий вид: acl.phtml:

<h2>Roles:</h2>
<ul>
    <?php 
        foreach ($this->roles as $name)
        {
            echo '<li><a href="'.$this->baseUrl('admin/acl') . '/role/' . $name . '">' . ucfirst($name) . '</a><br/></li>';
        }
    ?>
</ul>

<?php if (isset($this->controllers)): ?>
    <h2><?php echo ucfirst($this->role); ?>'s Controllers:</h2>
    <ul>
        <?php
            $array = $this->controllers;
            sort($array);
            foreach ($array as $controller)
            {
                $font = ($controller['allowed'])?'green':'red';
                echo '<li><a href="'.$this->baseUrl('admin/acl') . '/role/' . $this->role . '/cont/'.$controller['controller'].'" style="color:'.$font.';">'.ucfirst($controller['controller']).'</a></li>';    
            }   
        ?>
    </ul>

    <?php if (isset($this->controller)): ?>
        <h2><?php echo ucfirst($this->role)."'s, ".ucfirst($this->controller);?> Actions:</h2>
        <ul>
            <?php 
                $array = $this->actions;
                sort($array);
                foreach ($array as $action)
                {
                    $font = ($action['allowed'])?'green':'red';
                    echo '<li><font style="color:'.$font.';">'.ucfirst($action['action']).'</font></li>';
                }
            ?>
        </ul>
    <?php endif;?>
<?php endif; ?>

Пример:

image

Я надеюсь, что это кому-то полезно, я пока оставлю это открытым, если кто-нибудь может предложить лучшее решение- или, возможно, улучшить ответ?

1 голос
/ 28 апреля 2011
public function aclAction()
{
    $this->disableView();

    $service = $this->service()->acl();
    $acl = $service->getAcl();
    $roles = $acl->getRoles();
    $resources = $acl->getResources();
    $results = array();

    // load XML to get all rules & roles & actions
    $configdata = $service->getConfigdata();

    $actions = array();
    foreach ($configdata['rules']['rule'] as $rule){
        if(isset($rule['action'])){
            if(!is_array($rule['action']))
                $rule['action'] = array($rule['action']);
            foreach($rule['action'] as $action){
                $actions[$rule['resource']][$action] = $action;
            }
        }

    }

    $results[] =
    '<thead>'
    .   '<tr>'
    .       '<th>Resource</th>'
    .       '<th>Action</th>'
    .       '<th colspan="'.count($roles).'">Roles</th>'
    .   '</tr>'
    .   '<tr>'
    .       '<th></th>'
    .       '<th></th>';

    foreach ($roles as $role){
        $results[] = '<th>'.$role.'</th>' . PHP_EOL;
    }
    $results[] = '</tr></thead>' . PHP_EOL;
    $results[] = '<tbody>';

    foreach ($resources as $resource){

        $results[] = '<tr><th>'.$resource.'</th><td>-</td>';
        foreach ($roles as $role){
            $test = $acl->isAllowed($role, $resource);
            $results[] = '<td'.($test?' class="green"':' class="red"').'>'.($test?'YES':'NO').'</td>';
        }
        $results[] = '</tr>';

        if(isset($actions[$resource])){
            foreach ($actions[$resource] as $action){

                $results[] = '<tr><th>&rarr;</th><td>'.$action.'</td>';
                foreach ($roles as $role){
                    $test = $acl->isAllowed($role, $resource, $action);
                    $results[] = '<td'.($test?' class="green"':' class="red"').'>'.($test?'YES':'NO').'</td>';
                }
                $results[] = '</tr>';
            }
        }
    }

    echo
    '<style type="text/css">'
    .   'html, body, table {font-family:verdana;font-size:14px;}'
    .   'table {border-spacing:1px;background:#CCCCCC;}'
    .   'td, th {background:#ffffff;padding:5px;}'
    .   'th {text-align:left;}'
    .   'tr:nth-child(even) td, tr:nth-child(even) th {background:#C2DBEF;}'
    .   '.red {color:red;font-weight:bold;}'
    .   '.green {color:green;font-weight:bold;}'
    .'</style>'
    .'<h1>$role is allowed to $resource ?</h1>'
    .'<table>'.implode('', $results).'</table>';

}

Пример: http://i.stack.imgur.com/1tR3g.png (я не могу публиковать изображения в качестве гостя здесь) Я скопировал это из своего проекта - надеюсь, это поможет. Это выглядит очень хорошо в действии, но вам нужен правильно сформированный xml со всеми правилами и т. Д.

...