PHP MySQL Zend-ACL - 图形显示 ACL:

发布于 2024-10-08 12:50:17 字数 2045 浏览 1 评论 0 原文

我有一个像下面这样的 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)访问一个控制器。 用户是一种资源,控制器是一种资源)

使用 extras 列授予/拒绝对操作的访问权限。

这一切都有效,在 zend 中设置 ACL 不是问题。


我现在想做的是展示这些关系;为此,我需要找到授予角色访问控制器的最低级别,如果控制器已被明确删除,则停止。我计划列出角色。当我单击某个角色时,我希望它显示该角色有权访问的所有控制器。然后单击控制器会显示允许该角色执行的操作。

因此,在上面的示例中,访客可以查看索引控制器的索引操作以及登录操作。 成员继承相同的访问权限,但随后拒绝访问登录操作和注册操作。 版主继承会员的规则。

所以如果我要选择主持人的角色。我想查看列出的控制器索引。如果我单击控制器,它应该将允许的操作显示为 action:index.html。 (最初授予客人,但此后未被禁止)

是否有任何这样做的例子。显然我正在使用 Zend MVC (PHP) 和 MySQL。 即使只是一个伪代码示例也会是一个有用的起点 - 这是我正在组装的拼图的最后部分之一。

PS 显然我有 ACL 对象 - 查询它会更容易还是通过 PHP/MySQL 自己做更好?

目标是,显示角色可以访问什么,然后允许我以 GUI 样式添加或编辑角色、控制器和操作(这有点简单) - 目前我正在手动更新数据库我一直在建设该网站。

I have one MySQL DB table like the following, the resources table:

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

Onto the next table, the rules table:

+----+---------+------+-------------+----------------------+
| 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               |
+----+---------+------+-------------+----------------------+

OK, sorry for the length, but I am trying to give a full picture of what I am trying to do.
So the way it works, a role (aka user) can be granted (rule: 1) access to a controller, a role can inherit (rule: 3) access from another role or a role and be denied (rule: 2) access to a controller. (A user is a resource and a controller is a resource)

Access to actions are granted / denied using the extras column.

This all works, its not a problem with setting up the ACL within zend.


What I am now trying to do is show the relationships; to do that I need to find the lowest level a role is granted access to a controller stopping if it has explicitly been removed. I plan on listing the roles. When I click a role, I want it to show all the controllers that role has access to. Then clicking on a controller shows the actions the role is allowed to do.

So in the example above, a guest is allowed to view the index action of the index controller along with the login action.
A member inherits the same access, but is then denied access to the login action and register action.
A moderator inherits the rules of a member.

So if I were to select the role moderator. I want to see the controller index listed. If I click on the controller, it should show the allowed actions as being action: index. (which was originally granted to the guest, but hasn't since been dissallowed)

Is there any examples to doing this. I am obviously working with the Zend MVC (PHP) and MySQL.
Even just a persudo code example would be a helpful starting point - this is one of the last parts of the jigsaw I am putting together.

P.S. Obviously I have the ACL object - is it going to be easier to interigate that or is it better to do it my self via PHP/MySQL?

The aim will be, show what a role can access which will then allow me to add or edit a role, controller and action in a GUI style (that is somewhat the easy bit) - currently I am updating the DB manually as I have been building the site.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小情绪 2024-10-15 12:50:17

在我进行了一些搜索后,找不到答案,我对此进行了更多的思考,这是我想出的解决方案(以防万一对其他人有用)

伪优先:

  1. 显示一个页面,列出 ACL 中的所有角色(用户级别)$acl ->getRoles() 作为链接。
  2. 单击链接,重新加载页面,并将角色作为参数传递。
    • 现在从 ACL $acl->getResources() 获取所有控制器,检查资源是否不是角色 >(getResources 返回的数组也将包含角色)
    • 循环遍历每个控制器,从规则表中获取控制器 ID位于resource_id字段中的所有条目,并分解 >extras (逗号分隔的操作)
    • 接下来,循环遍历每个操作,调用isAllowed(我有角色、控制器和操作)如果至少找到一个“允许”,我将控制器着色为绿色(允许访问控制器中的至少一个操作),否则为红色(没有访问该控制器中的任何内容)每个列表项都可以单击以重新加载页面
  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; ?>

示例:

我希望这对某人有帮助,我现在将其保留,以防有人提出更好的解决方案 - 或者可能改进答案?

Well after I did abit of searching, and couldn't find an answer, I had a bit more of a think about this and here is the solution I came up with (just incase its useful for someone else):

Psuedo first:

  1. Show a page, listing all of the roles (user levels) from the ACL $acl->getRoles() as a link.
  2. Click a link, reload the page passing the role as a parameter.
    • Now grab all the controllers from ACL $acl->getResources() checking that the resource insn't a role (the array returned by getResources will also contain the roles).
    • loop through each controller, get all entries from the rules table where the controller id is in the resource_id field and explode the extras (comma seperated actions)
    • Next, loop through each action, calling isAllowed (I have the role, controller, and action). IF at least one "allowed" is found, I colour the controller green (allowed access to at least one action in the controller), otherwise its red (no access to anything in that controller) each list item being clickable to reload the page
  3. Now when a controller is clicked, I reload the page, now, when running through the list of actions, calling isAllowed I create a list of the actions for the selected controller, colouring the action green or red based on the result of isAllowed

The answer its self is almost as long winded as the question, but it works for me, giving a very clear picture of what each role can do. Here it is if its going to help anyone:

Now for the code:

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;
    }   
}

Next the view: 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; ?>

Example:

I hope this is helpful to someone, I will leave it open for now incase anyone can suggest a better solution - or maybe improve on the answer?

離殇 2024-10-15 12:50:17
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>→</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>';

}

示例: https://i.sstatic.net/1tR3g.png (我无法将图像发布为我是这里的客人)
我从我的项目中复制了它 - 希望它有帮助。它看起来非常好,但是您需要一个包含所有规则等且格式正确的 xml。

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>→</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>';

}

Example: https://i.sstatic.net/1tR3g.png (i cant post images as im a guest here)
I copied it from my project - hope it helps. It looks very nice in action but you need a properly formed xml with all the rules etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文