前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >ThinkPHP 3.2.3 简单后台模块开发(二)RBAC

ThinkPHP 3.2.3 简单后台模块开发(二)RBAC

作者头像
botkenni
发布于 2022-01-10 02:13:28
发布于 2022-01-10 02:13:28
2.1K00
代码可运行
举报
文章被收录于专栏:IT码农IT码农
运行总次数:0
代码可运行

RBAC(Role-Based Access Controll)基于角色的访问控制

在 ThinkPHP3.2.3 中 RBAC 类位于 /ThinkPHP/Library/Org/Util/Rbac.class.php

一、基本原理和数据库设计

在后台管理模块中,每个用户都属于相应的角色组,例如用户 admin 属于超级管理员角色组,用户 dee 属于普通管理员角色组,用户 jane 属于销售角色组,用户 nicole 属于财务角色组,每个角色组拥有的权限都不同。用户和角色组属于多对多的关系,即一个用户可能属于多个角色组,一个角色组有多个用户。

所有模块(例如 Home、Admin)、控制器(Controller)、方法(Action)都是节点,角色组是否能够访问这些节点的信息即是该角色组的权限信息。角色组和节点也是多对多的关系,即一个角色组可以访问多个节点,多个角色组都有可以访问同一个节点。

即 Rbac 功能需要 5 张数据表:用户表、角色表、用户-角色中间表、节点表、角色-节点中间表(权限表)。在 Rbac.class.php 中系统已经给出了其中的 4 张表:角色表(role)、用户-角色中间表(role_user)、节点表(node)、权限表(access):

4张表信息

需要自己创建一张用户表:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CREATE TABLE `crm_user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` char(20) NOT NULL DEFAULT '',
  `password` char(32) NOT NULL DEFAULT '',
  `logintime` int(10) unsigned NOT NULL,
  `loginip` varchar(30) NOT NULL,
  `lock` tinyint(1) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

数据模型如下:

基本的原理是,在配置文件中配置用户登录的识别号,这个识别号是用户的 id,在用户进行登陆的时候把 id 存储在 Session 中,同时根据 Session 保存的识别号通过连表查询获取该用户所属角色所能访问的节点信息并做判断。

二、配置选项

在 Rbac.class.php 中给出了需要配置的信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 配置文件增加设置
// USER_AUTH_ON 是否需要认证
// USER_AUTH_TYPE 认证类型
// USER_AUTH_KEY 认证识别号
// REQUIRE_AUTH_MODULE  需要认证模块
// NOT_AUTH_MODULE 无需认证模块
// USER_AUTH_GATEWAY 认证网关
// RBAC_DB_DSN  数据库连接DSN
// RBAC_ROLE_TABLE 角色表名称
// RBAC_USER_TABLE 用户表名称
// RBAC_ACCESS_TABLE 权限表名称
// RBAC_NODE_TABLE 节点表名称

在模块配置文件 ./Application/Admin/Conf/config.php 中添加:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//Rbac配置
    'RBAC_SUPERADMIN'=>'admin',         //超级管理员名称
    'ADMIN_AUTH_KEY'=>'superadmin',     //超级管理员识别,存放在Session中
    'USER_AUTH_ON'=>true,               //是否开启权限认证
    'USER_AUTH_TYPE'=>1,                //验证类型 1-登陆时验证 2-实时验证
    'USER_AUTH_KEY'=>'uid',             //存储在session中的识别号
    'NOT_AUTH_MODULE'=>'Index',              //无需验证的控制器
    'NOT_AUTH_ACTION'=>'add_role_handle',              //无需验证的方法
    'RBAC_ROLE_TABLE'=>'crm_role',      //角色表名称
    'RBAC_USER_TABLE'=>'crm_role_user', //角色与用户的中间表名称(注意)
    'RBAC_ACCESS_TABLE'=>'crm_access',  //权限表名称
    'RBAC_NODE_TABLE'=>'crm_node',      //节点表名称

三、RBAC 类源码分析

saveAccessList 方法:用于检测用户权限的方法,并保存到 Session 中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//用于检测用户权限的方法,并保存到Session中
    static function saveAccessList($authId=null) {
        if(null===$authId)   $authId = $_SESSION[C('USER_AUTH_KEY')];
        // 如果使用普通权限模式,保存当前用户的访问权限列表
        // 对管理员开发所有权限
        if(C('USER_AUTH_TYPE') !=2 && !$_SESSION[C('ADMIN_AUTH_KEY')] )
            $_SESSION['_ACCESS_LIST']    =    self::getAccessList($authId);
        return ;
    }

在登陆时调用,首先判断是否传递了用户识别号的参数,如果没有传递,就从 Session 中读取(配置文件中配置的用户识别号)对应的值;

如果配置的验证类型是登陆时验证(不是实时验证)同时该用户不是配置的超级管理员(Session 中不包含超级管理员识别号)时,就将调用 getAccessList 方法获取角色的权限。

getAccessList 方法

根据传递的用户识别号参数,通过连表查询(role、role_user、access、node)获得并返回该用户所属的角色组拥有的所有节点的权限 。

AccessDecision 方法

在 Common 控制器的 _iniatialize 方法中调用该方法。

如果当前访问的控制器和方法都不在不需要验证的节点信息(需要配置)中,那么调用该方法。

该方法首先调用 checkAccess 方法通过判断配置中是否开启 USER_AUTH_ON 来检查是否需要认证,如果开启了 USER_AUTH_ON ,则根据配置中需要验证和无需验证的模块的配置检查当前操作是否需要认证。

如果通过了 checkAccess 方法,则判断 Session 中由 saveAccessList 方法创建的_ACCESS_LIST 数组是否包含当前访问的模块、控制器和方法。超级管理员不由该方法进行认证。

四、开发实例

需要开发以下功能,顺序是:

①【添加角色 → 角色列表】 →

②【添加节点 → 节点列表】 →

③【权限列表 → 分配权限】 →

④【添加用户 → 用户列表 】 →

⑤【Rbac 配置】→

⑥【登陆】

在后台模块新建 Rbac 控制器:./Application/Admin/Controller/Rbac.class.php

① 角色

方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//角色列表
    public function role_list() {
        $this->role = M('role')->select();
        $this->display();
    }
    
    //添加角色
    public function add_role() {
        $this->display();
    }
    
    //添加角色表单处理
    public function add_role_handle() {
        if(M('role')->add($_POST)) {
            $this->success('添加成功',U('role_list','',''));
        } else {
            $this->error('添加失败');
        }
    }

视图:

添加角色(展示)./Application/Admin/View/Rbac_add_role.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html>
    <head>
    <title>添加角色</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="__PUBLIC__/Css/public.css"/>
    </head>
    <body>
        <form action="{:U('add_role_handle','','')}" method="post">
            <table class="table">
                <tr>
                    <th colspan="2">添加角色:</th>
                </tr>
                <tr>
                    <td align="right">角色名称:</td>
                    <td>
                        <input type="text" name="name" />
                    </td>
                </tr>
                <tr>
                    <td align="right">角色描述:</td>
                    <td>
                        <input type="text" name="remark" />
                    </td>
                </tr>
                <tr>
                    <td align="right">是否开启:</td>
                    <td>
                        <input type="radio" name="status" value="1" checked = "checked" />开启&nbsp;&nbsp;
                        <input type="radio" name="status" value="0" />关闭
                    </td>
                </tr>
                <tr>
                    <td colspan="2" align="center">
                        <input type="submit" value="保存添加">
                    </td>
                </tr>
            </table>    
        </form>
    </body>
</html>

角色列表 ./Application/Admin/View/Rbac_role_list.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="__PUBLIC__/Css/Public.css">
    </head>
    <body>
        <table class="table">
            <tr>
                <th>ID</th>
                <th>角色名称</th>
                <th>角色描述</th>
                <th>开启状态</th>
                <th>操作</th>
            </tr>
            <foreach name="role" item="v">
            <tr>
                <td>{$v.id}</td>
                <td>{$v.name}</td>
                <td>{$v.remark}</td>
                <td>
                    <if condition="$v['status'] eq 1">开启<else />关闭</if>
                </td>
                <td>
                    <a href="{:U('access',array('rid'=>$v['id']),'')}">配置权限</a>
                </td>
            </tr>
            </foreach>
        </table>
    </body>
</html>

② 节点

方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//节点列表
    public function node_list() {
        $field = array('id', 'name', 'title', 'pid');
        $node = M('node')->field($field)->order('sort asc')->select();
        $this->node = node_regroup($node);//p($this->node);die;
        $this->display();
    }
    
    //添加节点
    public function add_node() {
        $this->pid = I('get.pid', 0, 'int');//如果没有传递的pid参数,则默认为0
        $this->level = I('get.level', 1, 'int');//如果没有传递的level参数,则level是1,代表顶级(模块)
        switch($this->level) {
            case 1:
                $this->type = '模块';
                break;
            case 2:
                $this->type = '控制器';
                break;
            case 3:
                $this->type = '方法';
                break;
        }
        $this->display();
    }
    
    //添加节点表单处理
    public function add_node_handle() {
        if(M('node')->add($_POST)) {
            $this->success('添加成功',U('node_list','',''));
        } else {
            $this->error('添加失败');
        }
    }

视图:

添加节点 ./Application/Admin/View/Rbac_add_node.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="__PUBLIC__/Css/public.css">
</head>
<body>
    <form action="{:U('add_node_handle','','')}" method="post">
        <table class="table">
            <tr><th colspan="2">添加{$type}</th></tr>
            <tr>
                <td align="right">{$type}名称:</td>
                <td>
                    <input type="text" name="name" />
                </td>
            </tr>
            <tr>
                <td align="right">节点描述:</td>
                <td>
                    <input type="text" name="title">
                </td>
            </tr>
            <tr>
                <td align="right">是否开启:</td>
                <td>
                    <input type="radio" name="status" value="1" checked="checked" />开启
                    <input type="radio" name="status" value="0" />关闭
                </td>
            </tr>
            <tr>
                <td align="right">排序:</td>
                <td>
                    <input type="text" name="sort" />
                </td>
            </tr>
            <tr>
                <td colspan="2" align="center">
                    <input type="hidden" name="pid" value="{$pid}" />
                    <input type="hidden" name="level" value="{$level}" />
                    <input type="submit" value="添加{$type}" />
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

默认情况下从后台左侧栏目进行节点添加,添加的是模块(例如 Home 模块,Admin 模块)

节点列表 ./Application/Admin/View/Rbac_node_list.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="__PUBLIC__/Css/public.css">
</head>
<body>
    <div id="wrap">
        <a href="{:U('add_node','','')}">添加模块</a>
        <table class="table">
            <foreach name="node" item="app">
                <div class="app">
                    <p>
                        <strong>{$app.title}</strong>
                        <a href="{:U('add_node',array('pid'=>$app['id'],'level'=>2),'')}">
                            [添加控制器]
                        </a>
                        <a href="">[修改]</a>
                        <a href="">[删除]</a>
                    </p>
                    <foreach name="app.child" item="controller">
                        <dl>
                            <dt>
                                &nbsp;&nbsp;-
                                <strong>{$controller.title}</strong>
                                <a href="{:U('add_node',array('pid'=>$controller['id'],'level'=>3),'')}">
                                    [添加方法]
                                </a>
                                <a href="">[修改]</a>
                                <a href="">[删除]</a>
                            </dt>
                        
                        <foreach name="controller.child" item="method">
                            <div>
                                &nbsp;&nbsp;&nbsp;&nbsp;-
                                <strong>{$method.title}</strong>
                                <a href="">[修改]</a>
                                <a href="">[删除]</a>
                            </div>    
                        </foreach>
                        </dl>
                    </foreach>
                </div>
            </foreach>
        </table>
    </div>
</body>
</html>

此时可以通过 GET 传递 pid 和 level 添加控制器节点和方法节点,例如

在节点列表的方法中,需要用到递归重组节点信息,把在数据库 node 表中存储的节点信息按照层级(模块-控制器-方法的的层级)重新组合,结构类似于:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Array
(
    [0] => Array
        (
            [id] => 6
            [name] => Home
            [title] => 前台应用
            [pid] => 0
            [child] => Array
                (
                )

        )

    [1] => Array
        (
            [id] => 1
            [name] => Admin
            [title] => 后台应用
            [pid] => 0
            [child] => Array
                (
                    [0] => Array
                        (
                            [id] => 3
                            [name] => Index
                            [title] => 后台首页
                            [pid] => 1
                            [child] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 17
                                            [name] => index
                                            [title] => 后台首页
                                            [pid] => 3
                                            [child] => Array
                                                (
                                                )

                                        )

                                )

                        )

                    [1] => Array
                        (
                            [id] => 4
                            [name] => ArticleManage
                            [title] => 文章管理
                            [pid] => 1
                            [child] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 8
                                            [name] => index
                                            [title] => 文章列表
                                            [pid] => 4
                                            [child] => Array
                                                (
                                                )

                                        )

                                )

                        )

                    [2] => Array
                        (
                            [id] => 5
                            [name] => Rbac
                            [title] => 权限管理
                            [pid] => 1
                            [child] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 15
                                            [name] => user_list
                                            [title] => 用户列表
                                            [pid] => 5
                                            [child] => Array
                                                (
                                                )

                                        )

                                    [1] => Array
                                        (
                                            [id] => 14
                                            [name] => add_node_handle
                                            [title] => 添加节点表单处理
                                            [pid] => 5
                                            [child] => Array
                                                (
                                                )

                                        )

                                    [2] => Array
                                        (
                                            [id] => 13
                                            [name] => add_node
                                            [title] => 添加节点
                                            [pid] => 5
                                            [child] => Array
                                                (
                                                )

                                        )

                                    [3] => Array
                                        (
                                            [id] => 12
                                            [name] => node_list
                                            [title] => 节点列表
                                            [pid] => 5
                                            [child] => Array
                                                (
                                                )

                                        )

                                    [4] => Array
                                        (
                                            [id] => 11
                                            [name] => add_role_handle
                                            [title] => 添加角色表单处理
                                            [pid] => 5
                                            [child] => Array
                                                (
                                                )

                                        )

                                    [5] => Array
                                        (
                                            [id] => 10
                                            [name] => add_role
                                            [title] => 添加角色
                                            [pid] => 5
                                            [child] => Array
                                                (
                                                )

                                        )

                                    [6] => Array
                                        (
                                            [id] => 9
                                            [name] => role_list
                                            [title] => 角色列表
                                            [pid] => 5
                                            [child] => Array
                                                (
                                                )

                                        )

                                )

                        )

                )

        )

)

在 ./Application/Admin/Common/function.php 中创建方法 node_group

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php
/* 
 * 递归重组节点信息
 * @param $node 要重组的节点数组
 * @param $pid 父级ID
 * @return
 */
function node_regroup($node, $pid = 0, $access = null) {
    $arr = array();
    foreach($node as $v) {
        if(is_array($access)) {
            $v['access'] = in_array($v['id'], $access) ?  1 : 0;//判断是否已经拥有权限
        }
        if($v['pid'] == $pid) {
            $v['child'] = node_regroup($node, $v['id'], $access);
            $arr[] = $v;
        }
    }p($arr);
    return $arr;
}

③ 权限

方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//配置权限
    public function access() {
        $rid = I('get.rid', 0, 'int');//角色id
        $field = array('id', 'name', 'title', 'pid');
        $node = M('node')->field($field)->order('sort asc')->select();
        $access = M('access')->where('role_id = '.$rid)->getField('node_id', true);//已经拥有的权限
        $node = node_regroup($node, 0, $access); //递归节点 
        
        $this->rid = $rid;
        $this->node = $node;
        $this->display();
    }
    
    //权限配置的表单提交处理
    public function access_handle() {
        $rid = I('rid', 0, 'int');
        $db = M('access');
        $db->where('role_id = '.$rid)->delete();//删除原有权限
        $data = array();
        if(!empty($_POST['access'])) {
            foreach($_POST['access'] as $v) {
                $tmp = explode('_', $v);
                $data[] = array(
                    'role_id'=>$rid,
                    'node_id'=>$tmp[0],
                    'level'=>$tmp[1]
                );
            }
            if($db->addAll($data)) { //写入新权限
                $this->success('分配权限成功', U('role_list','',''));
            } else {
                $this->error('分配权限失败');
            }
        }
    }

视图:

从角色列表每一栏后面的“配置权限”点击进入

./Application/Admin/View/Rbac_access

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="__PUBLIC__/Css/public.css">
    <link rel="stylesheet" href="__PUBLIC__/Css/node.css">
    <script src="__PUBLIC__/Js/jquery-1.7.2.min.js"></script>
</head>
<body>
    <div id="wrap">
        <a id="return" href="{:U('role_list','','')}">返回</a>
        <form action="{:U('access_handle')}" method="post">
            <table class="table">
                <foreach name="node" item="app">
                    <div class="app">
                        <p>
                            <strong>{$app.title}</strong>
                            <input type="checkbox" name="access[]" value="{$app.id}_1" level="1" <if condition="$app['access'] eq 1">checked="checked"</if>>
                        </p>
                    <foreach name="app.child" item="controller">
                        <div class="app_child">
                            <dl class="controller">
                                <dt>
                                    <strong>{$controller.title}</strong>
                                    <input type="checkbox" name="access[]" value="{$controller.id}_2" level="2" <if condition="$controller['access'] eq 1">checked="checked"</if>>
                                </dt>
                            </dl>
                            <foreach name="controller.child" item="method">
                                <span class="method">
                                    <strong>{$method.title}</strong>
                                    <input type="checkbox" name="access[]" value="{$method.id}_3" level="3" <if condition="$method['access'] eq 1">checked="checked"</if>>
                                </span>    
                            </foreach>
                            <div style="clear:both"></div>
                        </div>
                    </foreach>
                    </div>    
                </foreach>
            </table>
            <input type="submit" value="提交"  style="display: block; margin:0 auto; cursor:pointer">
            <input type="hidden" name="rid" value="{$rid}">
        </form>
    </div>
</body>
<script>
    $(function(){
        $('input[level=1]').click(function(){
            var inputs = $(this).parents('.app').find('input');
            $(this).prop('checked') == true ? inputs.prop('checked', true) : inputs.prop('checked', false);
         });
         $('input[level=2]').click(function(){
             var inputs = $(this).parents('.app_child').find('input');
             $(this).prop('checked') == true ? inputs.prop('checked', true) : inputs.prop('checked', false);
         });
    });
</script>
</html>

④ 用户

方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//添加用户
    function add_user() {
        $this->role = M('role')->select();
        $this->display();
    }
    
    //添加用户的表单提交处理
    public function add_user_handle() {
        $user = array(
            'username'=>I('post.username', ''),
            'password'=>I('post.password','','md5'),
        );
        $uid = M('user')->add($user);
        $rold = array();
        if($uid) {
            foreach($_POST['role_id'] as $v) {
                $role[] = array(
                    'role_id'=>$v,
                    'user_id'=>$uid
                );
            }
            M('role_user')->addAll($role);
            $this->success('添加成功', U('user_list','',''));
        } else {
            $this->error('添加失败');
        }
    }
    
    //用户列表
    public function user_list() {
        $this->user = D('UserRelation')->field('password', true)->relation(true)->select();
        //P(D('UserRelation')->getLastSql());
        //p($this->user);
        //die;
        $this->display();
    }

关联模型

./Application/Admin/Model/UserRelationModel.class.php

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php
/*
 * 用户与角色关联模型
 */
namespace Admin\Model;
use Think\Model\RelationModel;

class UserRelationModel extends RelationModel{
    //定义主表名称
        protected $tableName = 'user';
    //定义关联关系
    protected $_link = array(
        'role'=>array(
            'mapping_type'=>self::MANY_TO_MANY,
            'foreign_key'=>'user_id',//指定主表外键
            'relation_key'=>'role_id',//指定关联表外键
            'relation_table'=>'crm_role_user',//指定中间表名称
            'mapping_fields'=>'id,name,remark'//读取的字段
        ),
    );
}

通过使用关联模型,使需要输出至 user_list 页面的数组以如下方式输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Array
(
    [0] => Array
        (
            [id] => 1
            [username] => admin
            [logintime] => 1454222361
            [loginip] => 127.0.0.1
            [lock] => 0
            [role] => Array
                (
                )

        )

    [1] => Array
        (
            [id] => 2
            [username] => dee
            [logintime] => 1454140261
            [loginip] => 127.0.0.1
            [lock] => 0
            [role] => Array
                (
                    [0] => Array
                        (
                            [id] => 2
                            [name] => Editor
                            [remark] => 网站编辑
                        )

                )

        )

)

模型查询的 SQL 语句类似于:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT b.id,name,remark FROM crm_role_user AS a, crm_role AS b WHERE a.role_id = b.id AND a. user_id='2'

视图:

添加用户 ./Application/Admin/View/Rbac_add_user.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <css file="__PUBLIC__/Css/public.css" />
    <js file="__PUBLIC__/Js/jquery-1.7.2.min.js" />
    <style>
        .add-role{
            display:inline-block;
            width:100px;
            height:26px;
            line-height: 26px;
            text-align: center;
            border: 1px solid  #ccc;
            border-radius: 4px;
            margin-left: 20px;
            cursor:pointer;
        }
    </style>
</head>
<body>
    <form action="{:U('add_user_handle','','')}" method="post">
        <table class="table">
            <tr>
                <th colspan="2">添加用户</th>
            </tr>
            <tr>
                <td align="right" width="40%">用户账号</td>
                <td>
                    <input type="text" name="username">
                </td>
            </tr>
            <tr>
                <td align="right">密码:</td>
                <td>
                    <input type="password" name="password">
                </td>
            </tr>
            <tr>
                <td align="right">所属角色:</td>
                <td>
                    <select name="role_id[]" id="">
                        <option value="">请选择角色</option>
                        <foreach name="role" item="v">
                            <option value="{$v.id}">{$v.name}({$v.remark})</option>
                        </foreach>
                    </select>
                    <span class="add-role">添加一个角色</span>
                </td>
            </tr>
            <tr id="last">
                <td colspan="2" align="center">
                    <input type="submit" value="保存">
                </td>
            </tr>
        </table>
    </form>
</body>
<script>
    $(function(){
        $(".add-role").click(function(){
            var obj = $(this).parents("tr").clone();
            obj.find(".add-role").remove();
            $("#last").before(obj);
        });
    });
</script>
</html>

用户列表 ./Application/Admin/View/Rbac_user_list.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="__PUBLIC__/Css/public.css">
</head>
<body>
    <table class="table">
        <tr>
            <th>ID</th>
            <th>用户名</th>
            <th>上一次登陆时间</th>
            <th>上一次登陆IP</th>
            <th>用户所属组</th>
            <th>是否锁定</th>
            <th>操作</th>
        </tr>
        <foreach name="user" item="v">
            <tr>
                <td>{$v.id}</td>
                <td>{$v.username}</td>
                <td>{$v.logintime|date="Y-m-d",###}</td>
                <td>{$v.loginip}</td>
                <td>
                    <if condition="$v['username'] eq C('RBAC_SUPERADMIN')">
                        超级管理员
                    <else/>
                    <ul>
                        <foreach name="v.role" item="value">
                            <li>{$value.name}({$value.remark})</li>
                        </foreach>
                    </ul>
                    </if>
                </td>
                <td>
                    <if condition="$v['lock'] eq 1">锁定<else/>正常</if>
                </td>
                <td><a href="">锁定</a></td>
            </tr>
        </foreach>
    </table>
</body>
</html>

④ 登陆和验证

登陆:

在 ./Application/Admin/Controller/LoginController.class.php 的 login 方法中添加:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//判断是否是超级管理员
        if($_SESSION['user']['username'] == C('RBAC_SUPERADMIN')) {
            session(c('ADMIN_AUTH_KEY'),true);
        }
        //读取用户权限
        RBAC::saveAccessList();

在 Common 控制器 (./Application/Admin/Controller/Common.class.php)的 _initialize 方法中添加验证:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$notAuth = in_array(CONTROLLER_NAME,explode(',',C('NOT_AUTH_MODULE'))) 
                || in_array(ACTION_NAME,C('NOT_AUTH_ACTION'));
        if(C('USER_AUTH_TYPE') && !$notAuth) {
            //var_dump(Rbac::AccessDecision());
            Rbac::AccessDecision() || $this->error('没有访问权限',U('Admin/Index/index'));
        }

Index 控制器中的登陆 longin、退出 loginout 等方法不需要权限认证,可以把 Index 控制器加入到无需认证的控制器中,一些表单提交处理的方法可以加入到无需认证的方法中。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017/01/04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
AppleWatch开发入门一——Watch的开发思路与应用框架
        Apple Watch无疑是apple在智能手表领域的一次革命,如何在Watch上开发出实用且具有美感的应用,是iOS开发者们开始思考的一个问题,由于watch的随身性和快捷性,在某些方面,它有比iphone更加大的优势,要抓住watch的这些特点,开发出淋漓尽致的应用,就需要改变一些在iphone开发的思路,正如一句话:只有忘掉经验,才会有意想不到的突破。
珲少
2018/08/16
2.2K0
AppleWatch开发入门一——Watch的开发思路与应用框架
AppleWatch开发入门七——watchOS中通知的应用
        在iOS系统中,支持的通知有两种类型:本地通知和远程通知。本地通知多用于计时类通知,远程的又称推送,多用于一些提示动态的提示信息。这里有相关通知的一些知识总结:
珲少
2018/08/15
1.6K0
AppleWatch开发入门五——菜单控件的使用
        菜单也是WatchOS中一个重要的交互方式,限于Watch的屏幕尺寸,若将所有用户交互控件都紧密的排列进展示的UI中,那样难免会使用户操作困难,也会影响界面布局的简洁美观。因此,WatchOS的菜单机制是一层覆盖在屏幕上的交互界面,有如下的特点:
珲少
2018/08/16
1.1K0
AppleWatch开发入门五——菜单控件的使用
AppleWatch开发入门三——代码交互与控制器生命周期
        在前两篇博客中,讨论了关于watch开发中框架与界面布局相关,然而主要的逻辑,终究还是要通过代码来实现的,在我们创建了项目之后,就会生成InterfaceController这个文件,它就是我们storyBoard中的入口视图控制器。
珲少
2018/08/16
1K0
AppleWatch开发入门三——代码交互与控制器生命周期
AppleWatch开发入门四——Table视图的应用
        WatchOS中的TableView和iOS中的TableView还是有很大的区别,在开发之前,首先我们应该明白WatchOS中的Table有哪些局限性和特点。下面几点是我总结WatchOS中Table的特殊之处:
珲少
2018/08/16
8710
AppleWatch开发入门四——Table视图的应用
AppleWatch开发入门二——界面布局 原
        在iphone开发中,最基本的布局方式是通过frame,将控件的位置和大小固定在屏幕上,后来,由于手机屏幕的尺寸有了略微变化,有了autoresizing的布局框架,我们可以设置子视图随父视图的改变做一些相应的变化,再后来,iphone的尺寸与分辨率也越来越多,适配各个屏幕也成为了iOS开发者遇到的新的问题,幸运的是,autolayout机制的出现,大大减小了开发者在适配方面的成本。以上提到的两种布局方式,在以前博客中有讨论:
珲少
2018/08/16
7820
AppleWatch开发入门二——界面布局
                                                                            原
AppleWatch开发入门九——Watch帧动画的实现
        动画一直是iOS系统的一大亮点,CoreAnimation和粒子效果的支持,开发者可以很容易的做出效果炫酷的动画特效。在watchOS中,由于性能和屏幕尺寸的限制,对于动画,并没有强大的框架支持,但是这并不是说开发者就没办法在watch上添加动画的特效了。在watchOS中唯一可以让开发者用于动画操作的就是帧动画。
珲少
2018/08/15
9740
AppleWatch开发入门九——Watch帧动画的实现
iOS中Today扩展插件与宿主APP的交互 原
        扩展是iOS8后系统开发给开发者的新开发思路与接口,每一个扩展都可以理解为一个简单的小应用程序,只是其不是独立存在的,要寄附于某一个主应用上。介绍iOS8扩展与Today插件的专题见如下博客:
珲少
2018/08/15
1.7K0
iOS中Today扩展插件与宿主APP的交互
                                                                            原
WatchKit 编程入门
AppleWatch 是由苹果公司创造的智能手表,TimCook 于 2014 年 9月9日在苹果公司官方发布会上宣布了这一消息。AppleWatch 是继 iPhone 和 iPad 之后苹果公司的又一力作,苹果公司希望借此改变可穿戴设备的规则(就像 iPhone 改变了智能手机,iPad 改变了平板一样)。
博文视点Broadview
2020/06/11
2K0
iOS8新特性扩展(Extension)应用之一——Today扩展
        基于iOS系统的安全性考虑,其应用的数据存储是通过沙盒模式进行的,要实现应用之间的数据共享十分困难,功能共享就更加棘手。在iOS8系统中,apple为我们提供了一个革命性的功能:扩展。我们可以通过扩展来使app间数据甚至功能进行共享。
珲少
2018/08/16
5210
iOS8新特性扩展(Extension)应用之一——Today扩展
iOS9系列专题一——3D Touch 原
        在iphone6s问世之后,很多果粉都争先要体验3D Touch给用户带来的额外维度上的交互,这个设计之所以叫做3D Touch,其原理上是增加了一个压力的感触,通过区分轻按和重按来进行不同的用户交互。
珲少
2018/08/16
6330
iOS9系列专题一——3D Touch
                                                                            原
iWatch开发:WatchOS 消息推送教程
在watch 中,通知是和iPhone 同步的,在iPhone上的APP收到通知的同事,也会默认推送到iWatch 上,基于watch 的穿戴性,对用户来说,它上面的通知信息将比iPhone更及时。
HelloWorld杰少
2022/08/03
1.5K0
iWatch开发:WatchOS 消息推送教程
iOS8新特性扩展(Extension)应用之三——照片编辑插件
        通过前几篇博客的介绍,我们了解到扩展给app提供的更加强大的交互能力,这种强大的交互能力另一方面体现在照片编辑插件的应用。
珲少
2018/08/16
3790
iOS8新特性扩展(Extension)应用之三——照片编辑插件
你想知道的 Watch App 开发
你创建的 Apple Watch 工程由两个相关的 bundle 组成:一个 Watch app bundle 和 一个WatchKit extension bundle。Watch app bundle 里面包含了 storyboards 以及一系列与你的app 界面相关的资源文件。WatchKit extension bundle 位于 Watch app bundle 内,包含用于管理这些界面和响应用户互动的代码。这两个包统称为 Watch app。你发布的 Watch app 存在于你的iOS 应用程序中,iOS app 会将watch app 的应用程序复制到用户的Apple Watch中,然后在本地运行。
HelloWorld杰少
2022/08/03
1.1K0
iOS9新特性——堆叠视图UIStackView
        随着autolayout的推广开来,更多的app开始使用自动布局的方式来构建自己的UI系统,autolayout配合storyBoard和一些第三方的框架,对于创建约束来说,已经十分方便,但是对于一些动态的线性布局的视图,我们需要手动添加的约束不仅非常多,而且如果我们需要插入或者移除其中的一些UI元素的时候,我们又要做大量的修改约束的工作,UIStackView正好可以解决这样的问题。
珲少
2018/08/15
2.5K0
iOS9新特性——堆叠视图UIStackView
iOS对UIViewController生命周期和属性方法的解析
        作为MVC设计模式中的C,Controller一直扮演着项目开发中最重要的角色,它是视图和数据的桥梁,通过它的管理,将数据有条有理的展示在我们的View层上。iOS中的UIViewController是UIKit框架中最基本的一个类。从第一个UI视图到复杂完整项目,都离不开UIViewController作为基础。基于UIViewController的封装和扩展,也能够出色的完成各种复杂界面逻辑。这篇博客,旨在讨论UIViewController的生命周期和属性方法,在最基础的东西上,往往会得到意想不到的惊喜。
珲少
2018/08/16
3.2K0
iOS对UIViewController生命周期和属性方法的解析
IOS入门之StoryBoard
概述 在iOS的发展历程中,IOS开发经历了三种主要流派:使用代码手写UI及布局;使用单个xib文件组织viewController或者view;使用StoryBoard来通过单个或很少的几个文件构建全部UI。而在最近几年的开发中,苹果对 Storyboard 的开发力度也不断增强,添加了更多功能和特性,大大方便了界面的开发、适配以及提升代码性能。 我们来看看三种方式的主要区别: 手写页面和逻辑代码 如果你的目的是写一些可以高度重用的控件提供给其他开发者使用,那毫无疑问最好的选择应该是使用代码来完成UIVi
xiangzhihong
2018/02/06
1.9K0
IOS入门之StoryBoard
iOS10通知框架UserNotification理解与应用
        关于通知,无论与远程Push还是本地通知,以往的iOS系统暴漏给开发者的接口都是十分有限的,开发者只能对标题和内容进行简单的定义,至于UI展示和用户交互行为相关的部分,开发者开发起来都十分困难。至于本地通知,iOS10之前采用的是UILocationNotification类,远程通知有苹果服务器进行转发,本地通知和远程通知其回调的处理都是通过AppDelegate中的几个回调方法来完成。iOS10系统中,通知功能的增强是一大优化之处,iOS10中将通知功能整合成了一个框架UserNotification,其结构十分类似于iOS8中的UIWebView向WebKit框架整合的思路。并且UserNotification相比之前的通知功能更加强大,主要表现在如下几点:
珲少
2018/08/15
2K0
iOS10通知框架UserNotification理解与应用
iOS界面布局之三——纯代码的autoLayout及布局动画
        关于界面布局,apple的策略已经趋于成熟,autolayout的优势在开发中也已经展现的淋漓尽致。除了使用storyBoard进行布局约束的拖拽,有时我们也需要在代码中进行autolayout的布局设置,Masonry库可以方便的创建约束属性,实际上,我们也没有必要再使用系统原生的代码来创建和设置约束,这篇博客只作为使用的方法备忘。前几篇布局介绍的链接如下:
珲少
2018/08/15
3K0
iOS界面布局之三——纯代码的autoLayout及布局动画
iOS开发常用之测试调试、动态更新
测试及调试 HeapInspector - HeapInspector是一个用于检测应用程序的内存泄漏的开源调试工具。 Crashlytics - Crashlytics崩溃报告崩溃日志使用说明 。 UIViewController-Swizzled - 把你进入的每一个控制器的类名打出来,如果看一些特别复杂的项目的时候直接运行demo就可以知道执行次序了。 snoop-it -snoop-it比UIViewController-Swizzled好用,代码托管在谷歌上。 版本 - 版本
GuangdongQi
2018/12/14
3.8K0
推荐阅读
相关推荐
AppleWatch开发入门一——Watch的开发思路与应用框架
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档