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):

/*
-- --------------------------------------------------------
CREATE TABLE IF NOT EXISTS `think_access` (
`role_id` smallint(6) unsigned NOT NULL,
`node_id` smallint(6) unsigned NOT NULL,
`level` tinyint(1) NOT NULL,
`module` varchar(50) DEFAULT NULL,
KEY `groupId` (`role_id`),
KEY `nodeId` (`node_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `think_node` (
`id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`title` varchar(50) DEFAULT NULL,
`status` tinyint(1) DEFAULT '0',
`remark` varchar(255) DEFAULT NULL,
`sort` smallint(6) unsigned DEFAULT NULL,
`pid` smallint(6) unsigned NOT NULL,
`level` tinyint(1) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `level` (`level`),
KEY `pid` (`pid`),
KEY `status` (`status`),
KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `think_role` (
`id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`pid` smallint(6) DEFAULT NULL,
`status` tinyint(1) unsigned DEFAULT NULL,
`remark` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `pid` (`pid`),
KEY `status` (`status`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ; CREATE TABLE IF NOT EXISTS `think_role_user` (
`role_id` mediumint(9) unsigned DEFAULT NULL,
`user_id` char(32) DEFAULT NULL,
KEY `group_id` (`role_id`),
KEY `user_id` (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
*/

4张表信息

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

CREATE TABLE `crm_user` (
`id` int() unsigned NOT NULL AUTO_INCREMENT,
`username` char() NOT NULL DEFAULT '',
`password` char() NOT NULL DEFAULT '',
`logintime` int() unsigned NOT NULL,
`loginip` varchar() NOT NULL,
`lock` tinyint() unsigned NOT NULL DEFAULT '',
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 3.2.3 简单后台模块开发(二)RBAC的更多相关文章

  1. ThinkPHP 3.2.3 简单后台模块开发(一)常用配置

    一.项目分组 下载解压 ThinkPHP 3.2.3,在默认的应用 Application(./Application) 中,包含一个默认的模块 Home(./Application/Home). 需 ...

  2. VueJS搭建简单后台管理系统框架 (二) 模拟Ajax数据请求

    开发过程中,免不了需要前台与后台的交互,大部分的交互都是通过Ajax请求来完成,在服务端未完成开发时,前端需要有一个可以模拟Ajax请求的服务器. 在NodeJs环境下,通过配置express可访问的 ...

  3. PHPCMS V9 模块开发 二次开发实例 留言本

    鄙人实现了PHPCMS V9 产品开发权威指南(2011官方最新版).doc中的留言板实例,并加上模块安装和卸载功能, 程序可以运行,但只实现基本功能,目的是想让和我一样徘徊在PHPCMS门口不知道从 ...

  4. angular之模块开发二

    一.模块化规范 1.服务器端规范 CommonJS--node.js 2.浏览器端规范 AMD--RequireJS 国外相对流行 CMD--SeaJS 国内相对流行 3.模块化框架实现 CMD实现- ...

  5. ThinkPHP Widget模块开发流程

    初识ThinkPHP的Widget,现把模块开发的流程发布如下,也方便以后自己查阅: 一.新建数据库表self_modules,sql代码如下 CREATE TABLE `self_modules` ...

  6. 基于ASP.NET MVC的热插拔模块式开发框架(OrchardNoCMS)--模块开发

    之前文章中给大家说明了下我这个小小的想法,发现还是有不少人的支持和关注.你们的鼓励是对我最大的支持. 我总结了了大家的评论,有以下几个问题: 1.希望有更多的文档说明. 2.希望介绍下Orchard的 ...

  7. Asp.net Mvc模块化开发之“开启模块开发、调试的简单愉快之旅”

    整个世界林林种种,把所有的事情都划分为对立的两个面. 每个人都渴望的财富划分为富有和贫穷,身高被划分为高和矮,身材被划分为胖和瘦,等等. 我们总是感叹,有钱人的生活我不懂;有钱人又何尝能懂我们每天起早 ...

  8. thinkphp 的两种建构模式 第一种一个单入口里面定义两个模块,前台和后台,函数控制模块必须function.php前台加载前台模块的汉书配置文件,后台加载后台模块的汉书配置文件,公共文件共用。第二种架构模式两个单入口文件,分别生成两个应用定义define。。。函数可以定义配置文件。。。。

    thinkphp 的两种建构模式  第一种一个单入口里面定义两个模块,前台和后台,函数控制模块必须function.php前台加载前台模块的汉书配置文件,后台加载后台模块的汉书配置文件,公共文件共用. ...

  9. TERSUS无代码开发(笔记08)-简单实例电脑端后台逻辑开发

    主管审批功能逻辑开发 1.查询逻辑开发(查询待审批记录) 2.批准处理(将选中的一条记录进行批准处理)  =============================================== ...

随机推荐

  1. WPF ,listbox,平滑滚动的2种方式。

    一,烤地瓜版本的..  这个版本不安装内容滚动,,鼠标滑轮滚动一次距离相同, 具体步骤参照他的博客,说点注意的,, 1,ScrollViewer.CanContentScroll="Fals ...

  2. Flume interceptor 使用注意事项

    1. 在使用 Regex Filtering Interceptor的时候一个属性是excludeEvents 当它的值为true 的时候,过滤掉匹配到当前正则表达式的一行 当它的值为false的时候 ...

  3. Ue4 Shader博客

    http://blog.csdn.net/noahzuo/article/details/51133166 国外HLSL网站 https://www.shadertoy.com/browse

  4. kafka storm hbase性能

    kafka  单台机器部署 1个partition storm 单台机器部署 hbase 四台机器集群 机器配置大概是4G cpu 4G内存 从kafka 读出到storm,然后flush到hbase ...

  5. C#调用本机摄像头

    这段时间一个小项目中需要调用本机的摄像头进行拍照,网上搜集了一些资料以及解决的一些小问题,在此记录以便后续使用. 硬件环境:联想C360一体机,自带摄像头 编写环境:vs2010 语言:C# WPF ...

  6. Android作业分组与选题

    期末大作业 序号 题目 组员分工 完成度 1 基于安卓系统的游戏开发 2 设计一个安卓手机小游戏 3 Android平台应用——音乐播放器设计 4 基于Android技术的个人博客 5 电子阅读器 6 ...

  7. 如何提升 service 等级,不被kill(整合)

    (1)在应用退到后台后,另起一个只有1像素的页面停留在桌面上,让自己保持前台状态,保护自己不被后台清理工具杀死. (2)用Foreground Service. 参考地址:Android Servic ...

  8. ACM: Racing Gems - 最长递增序列

    Racing Gems   You are playing a racing game.  Your character starts at the x axis (y = 0) and procee ...

  9. Linux_解决nohup命令生成的多余的大日志文件

    解决nohup命令生成的多余的大日志文件 经常使用命令 nohup /usr/bin/php /srv/www/update.php & 可以让它在后台安静的进行,但是有一个烦恼就是,它会生成 ...

  10. supervisor、pm2、forever坐下来聊聊

    supervisor 是开发环境用.或者用nodemon,node-dev 代替了supervisor 和 nodemon,它和coffeescript兼容最好. forever 管理多个站点,每个站 ...