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张表信息

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

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 中给出了需要配置的信息:

// 配置文件增加设置
// 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 中添加:

    //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 中

    //用于检测用户权限的方法,并保存到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

① 角色

方法:

    //角色列表
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

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

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

② 节点

方法:

    //节点列表
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

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

<!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 表中存储的节点信息按照层级(模块-控制器-方法的的层级)重新组合,结构类似于:

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

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

③ 权限

方法:

    //配置权限
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

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

④ 用户

方法:

    //添加用户
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

<?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 页面的数组以如下方式输出:

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 语句类似于:

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

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

<!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 方法中添加:

        //判断是否是超级管理员
if($_SESSION['user']['username'] == C('RBAC_SUPERADMIN')) {
session(c('ADMIN_AUTH_KEY'),true);
}
//读取用户权限
RBAC::saveAccessList();

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

        $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 控制器加入到无需认证的控制器中,一些表单提交处理的方法可以加入到无需认证的方法中。

注:后台模板来自后盾网提供的免费下载

ThinkPHP的Rbac权限控制的更多相关文章

  1. 基于thinkphp的RBAC权限控制

    RBAC  Role-Based Access Control 权限控制在后台管理中是十分常见的,它的模型大体上是下面这张图的形式 我用的字段和上面不一样,图只是个示例 一个简易的权限控制模型只需要3 ...

  2. yii2 rbac权限控制详细操作步骤

    作者:白狼 出处:http://www.manks.top/article/yii2_rbac_description本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 ...

  3. yii2 rbac权限控制之菜单menu详细教程

    作者:白狼 出处:http://www.manks.top/article/yii2_rbac_menu本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则 ...

  4. yii2搭建完美后台并实现rbac权限控制实例教程

    1.安装yii2 未安装的请参考yii2史上最简单式安装教程,没有之一 或者参考yii2实战教程之详细安装步骤 已安装的请继续看下一步操作 2.配置数据库 2.1 配置数据库 修改common/con ...

  5. Kubernetes-16:一文详解ServiceAccount及RBAC权限控制

    一.ServiceAccount 1.ServiceAccount 介绍 首先Kubernetes中账户区分为:User Accounts(用户账户) 和 Service Accounts(服务账户) ...

  6. ThinkPHP中:RBAC权限控制的实习步骤

    使用版本ThinkPHP3.1.3 第一步,建表及数据 第二步,建关联模型 第三步,控制器使用关联模型.配置文件 第四步,模板显示数据 第一步,建表及数据 在数据库中,建立一个companysvn数据 ...

  7. yii2搭建完美后台并实现rbac权限控制案例教程

    作者:白狼 出处:www.manks.top/article/yii2_frame_rbac_template 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连 ...

  8. ThinkPHP中RBAC权限带菜单栏显示和详细权限操作

    RBAC是什么,能解决什么难题? RBAC是Role-Based Access Control的首字母,译成中文即基于角色的权限访问控制,说白了也就是用户通过角色与权限进行关联[其架构灵感来源于操作系 ...

  9. ThinkPHP中RBAC权限管理的简单应用

    RBAC英文全称(Role-Based Access Controller)即基于角色的权限访问控制,简单来讲,一个用户可以拥有若干角色,每一个角色拥有若干权限.这样,就构造成“用户-角色-权限”的授 ...

随机推荐

  1. ../../../../.. 太low了

    痛点 如果我们有这个目录: ├── webpack.config.js ├── src │ ├── view │ │ ├── index.js │ │── router │ │ ├── index.j ...

  2. Problem Q

    Problem Description A factory produces products packed in square packets of the same height h and of ...

  3. 默认权限umask、文件系统权限、特殊权限

    第1章 权限相关错误 1.1 普通用户 ls /root/ /root  属于root 普通用户没有任何权限,所以无法查看 [oldboy@znix ~]$ ls /root/ ls: cannot ...

  4. Dapper.Contrib——更加优雅地使用Dapper进行增删改查

    简介 Dapper是介于Entity framework与ADO的折中选择.既满足手写查询的高性能需求,又简化了数据库对象映射为内存对象的繁杂工作.Dapper.Contrib是对Dapper的进一步 ...

  5. JavaScript系列----作用域链和闭包

    1.作用域链 1.1.什么是作用域 谈起作用域链,我们就不得不从作用域开始谈起.因为所谓的作用域链就是由多个作用域组成的.那么, 什么是作用域呢? 1.1.1作用域是一个函数在执行时期的执行环境. 每 ...

  6. [转载] Hibernate与 MyBatis的比较

    转载自http://blog.csdn.net/firejuly/article/details/8190229 最近做了一个Hibernate与MyBatis的对比总结,希望大家指出不对之处. 第一 ...

  7. JavaScript学习笔记(二)——字符串

    在学习廖雪峰前辈的JavaScript教程中,遇到了一些需要注意的点,因此作为学习笔记列出来,提醒自己注意! 如果大家有需要,欢迎访问前辈的博客https://www.liaoxuefeng.com/ ...

  8. [转]Android应用安装包apk文件的反编译与重编译、重签名

    背景介绍: 最近在做Robotium自动化测试,使用到solo.takeScreenshot()函数以在测试过程中截图,但此函数需要被测试APP具有<uses-permission androi ...

  9. 熟悉的“if __name__ == '__main__':”究竟是啥?

    print(__name__) # 直接手动运行,打印"__main__",当做模块导入(别处import)时打印脚本名字即"name_main" if __n ...

  10. jfinal 源码学习

    源由 最近闲来无事,顺带看了下jfinal的源码,以下均为自己的个人理解,如有错误请指定: jfinal 使用 在web.xml中配置JfinalFilter 并定义JfinalConfig的类 自定 ...