现在说到权限认证的方式一般都是rbac,onethink使用了扩展的Auth 类来代替rbac作为权限认证的方式。下面我们来看看ot是怎么使用auth类实现其系统的权限认证的。
首先auth类比rbac类更加的可扩展,现在的系统权限认证都是根据url来区分的,程序会根据传入的url来分离出一个标志着此url唯一性的字符串A,然后从数据库中得到该登录用户的权限字符串,如果这个权限字符串中含有这个唯一性的字符串A,那么说明这个用户是可以访问这个url的,说明此用户对于此url是有访问权限的。
rbac作为权限认证方式,他一般只细化到了节点,即mvc菜单控制。如果是比较细化的按钮访问控制就比较麻烦了。而auth是按照规则来进行权限认证的。Auth权限认证是按规则进行认证。我先说说它的原理。 在数据库中我们有 规则表(think_auth_rule) ,用户组表(think_auth_group), 用户组明显表(think_auth_group_access)
我们在规则表中定义权限规则 , 在用户组表中定义每个用户组有哪些权限规则,在用户组明显表中 定义用户所属的用户组。 下面举例说明。
我们要判断用户是否有显示一个操作按钮的权限, 首先定义一个规则, 在规则表中添加一个名为 show_button 的规则。 然后在用户组表添加一个用户组,定义这个用户组有show_button 的权限规则(think_auth_group表中rules字段存得时规则ID,多个以逗号隔开), 然后在用户组明细表定义 UID 为1 的用户 属于刚才这个的这个用户组。
下面我们来看ot的权限检测流程:
首先我们要知道程序是怎么实现权限检测的。从http请求说起,浏览器和服务器的数据交互是通过get和post的方式来进行的,所以url在这里会是非常重要,服务器端通过url来区分客户端的请求,那么就要对这些请求进行权限拦截放行就要依靠url,而url之间是怎么区分的,就是通过url的参数。比如http://www.daydaytc.com/wp-admin/post.php?post=294&action=edit和http://www.daydaytc.com/wp-admin/post.php?post=294&action=add就是两个不同的url,因为其action参数不同,那么服务器端程序就可以对其进行权限判断和拦截,怎么拦截呢?
根据url的形式不同,我们可以把权限分为动态权限和非动态权限。先说非动态权限,这是一种非常常见的权限,这种权限下我们的url是固定设计好的,每个设计好的url对应后台的一个控制器的方法,比如Admin/model/add 和Admin/model/update,这就是两个http://www.daydaytc.com?s=Admin/model/add和http://www.daydaytc.com?s=Admin/model/update url的权限规则,这样程序就能检测组合出mvc参数,并组合出这个规则,然后通过当前登录用户得到当前用户的所属组,通过组得到组的权限列表,看这个权限规则是否在这个权限列表中,如果在的话说明已授权,不在的话说明没有权限。这就是一个完整的权限设计流程。一般我么处理的也都是这类权限,比如我们后台添加一个菜单,并且给菜单一个控制器方法,然后可以给菜单授权,这个菜单就是一个非动态权限,在我们添加完这个菜单后就会定义这个菜单的mvc参数,这就是规则。
但是我们的系统中并不是只有菜单需要进行权限控制,凡是有url访问入口的都有可能成为权限控制的对象,比如我们新建了一篇文档希望进行权限控制,比如我们新建立了一个分类希望进行权限控制,不可能我们每创建一个分类就为这个分类添加一个节点,更不可能每添加一篇文档就为这篇文档添加一个节点,这样不仅管理麻烦而且节点数量也会爆炸性增长,因此这个时候就需要动态权限控制,需要写一段程序来检测此类url。
下面来看ot是怎么处理动态权限的。
ot的分类授权就是使用这个实现的。
要实现一个完整的权限管理程序的步骤总共分几步:首先创建一个权限规则,第二步为某个用户组授权,第三步在控制器中写入自己的逻辑动态判断权限(根据用户uid会获得所属的用户组,根据用户组获得权限列表,判断现在的id是否在权限列表中。下面来看看ot是怎么通过auth的扩展权限实现分类授权的。
首先其有一张表,auth_extend,里面保存三个字段,分别是组id,数据id和类型id,代表的意思是某个组对某个权限类型的某个数据有权限. 比如对分类授权,分类的类别id就是资源id。
其次是该表的模型类,AuthGroupModel,
里面有个通用的方法addToExtend,主要用来往auth_extend数据表中添加一条数据, static public function addToExtend($gid,$cid,$type) 看传入的三个参数即用户组id,数据id和类型id。
还有一个通用的方法getAuthExtend,主要用来从auth_extend数据表中获取一条数据static public function getAuthExtend($uid,$type,$session)
看分类授权功能编写的步骤:
1: 在后台权限管理页面写入一个分类授权的链接
编辑admin/auth_manager/index.html模板,加入一个<a href=”{:U(‘AuthManager/category?group_name=’.$vo[‘title’].’&group_id=’.$vo[‘id’])}” >分类授权</a>
2:点击上述链接会进入一个页面,在这个页面可以对某个用户组进行类别授权,授权 信息会写入auth_extend表中
此链接指向。
这里编辑admin/auth_manager/category.html
3: 在category.html提交后的控制器代码中使用addToExtend把分类的权限设定写入auth_extend表
4:在控制器中进行权限检测,使用getAuthExtend方法根据用户id,查出用户所属用户组group_id,根据group_id,从auth_extend表以type=1为条件查出了extend_id,即用户拥有权限的分类。
5:当前分类和从查出来的分类数组进行比较,如果存在在数组中说明有权限,没有说明没权限。
下面来看看后台权限判断的流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
/**
* 后台控制器初始化
*/
protected
function
_initialize
(
)
{
// 获取当前用户ID
define
(
'UID'
,
is_login
(
)
)
;
if
(
!
UID
)
{
// 还没登录 跳转到登录页面
$this
->
redirect
(
'Public/login'
)
;
}
/* 读取数据库中的配置 */
$config
=
S
(
'DB_CONFIG_DATA'
)
;
if
(
!
$config
)
{
$config
=
api
(
'Config/lists'
)
;
S
(
'DB_CONFIG_DATA'
,
$config
)
;
}
C
(
$config
)
;
//添加配置
// 是否是超级管理员
define
(
'IS_ROOT'
,
is_administrator
(
)
)
;
// 检测访问权限
//调用accessControl方法,该方法是权限检测的第一个指定的方法,在此方法内主要执行的逻辑是特殊节点检测。组合出执行方法的路径方法名称,如果ALLOW_VISIT检测通过,直接放行访问。如果DENY_VISIT检测通过,直接拒绝。如果二者都未通过,则会进入下一步权限检测。
$access
=
$this
->
accessControl
(
)
;
if
(
$access
===
false
)
{
$this
->
error
(
'403:禁止访问'
)
;
}
elseif
(
$access
===
null
)
{
//checkDynamic方法是执行动态权限,此方法主要用于二次开发的扩展。
$dynamic
=
$this
->
checkDynamic
(
)
;
//检测分类栏目有关的各项动态权限
if
(
$dynamic
===
null
)
{
//检测非动态权限,这里检测非动态权限的扩展,主要是组合出mvc的执行方法路径,调用auth类的checkrule方法检测权限
$rule
=
strtolower
(
MODULE_NAME
.
'/'
.
CONTROLLER_NAME
.
'/'
.
ACTION_NAME
)
;
if
(
!
$this
->
checkRule
(
$rule
,
array
(
'in'
,
'1,2'
)
)
)
{
$this
->
error
(
'提示:无权访问,您可能需要联系管理员为您授权!'
)
;
}
}
elseif
(
$dynamic
===
false
)
{
$this
->
error
(
'提示:无权访问,您可能需要联系管理员为您授权!'
)
;
}
}
$this
->
assign
(
'__controller__'
,
$this
)
;
}
|