半年前,TP5.0发布了,它相对完整的文档出来了之后,云天河去通读了一次,感觉它更像Laraval了,更是察觉PHP框架目前正趋向于一个标准化,里面的带有的一些功能也是有异曲同工之处
这次主要讲讲Auth的实现过程
它是一种按web节点认证的方式,思想如下:
一个用户,可以对应多个用户组,
如果当前用户所在的角色组中,包含该节点,则有访问该节点的权限。
否则拒绝访问该节点。
其过程大致如下
接收 用户的id => uid
查询用户对应的规则字符串组,接着查询出所有的规则号 => array_merge
合并规则号时,数组键值去重 => array_unique
查询规则名称,若是选择认证url模式,则auth类会帮你把传入的$rule与所有规则名称转为小写,方便比较
情况1
若是配置的登陆时认证,会将规则列表的数组,存在session中,以后判断Auth的时候,会直接执行Step6
情况2
若是配置的实时认证,则每次都得查询数据库,并返回规则列表的数组
查询规则名称的数组中是否有对应的规则名 => in_array
一般不会用到,但还是得讲讲
在Step4中,取出规则名称的过程中,规则名列表,是通过循环添加到该数组尾部的
若要配置condition字段,则要写成 {用户表中字段名} 的形式
示例: {score}>5
验证时,如果condition字段不为空,如, {score}>5
验证过程如下:
1)该用户[默认是uid字段]对应的用户表中,所有字段的值
2) 取出当前用户score字段的值,如,当前用户对应的score值为3
/**
* 先取出condition字段中的名称,存入,$rule['condition'] 中,如,“score”
* 通过正则替换,拼接为条件字符串,
*/
$this_condition = preg_replace('/\{(\w*?)\}/', '$user[\'\\1\']', $rule['condition']);
//形如 $this_condition = "3>5";
3)用eval()将条件的字符串变为可执行的参数,如
$this_condition = " return $this_condition ; ";
4)判断该参数是否满足条件,若正确,则添加该字段名到数组尾部
if( @eval($this_condition) ){
$rule['name'][] = $rule['condition'];
}
// 默认配置
protected $_config = array(
'AUTH_ON' => true, // 认证开关
'AUTH_TYPE' => 2, // 认证方式,1为实时认证;2为登录认证。
'AUTH_GROUP' => 'hlz_auth_group', // 用户组数据表名
'AUTH_GROUP_ACCESS' => 'hlz_auth_group_access', // 用户-用户组关系表
'AUTH_RULE' => 'hlz_auth_rule', // 权限规则表
'AUTH_USER' => 'hlz_user' // 用户信息表
);
################数据库操作--复制开始################
-- ----------------------------
-- hlz_auth_rule,规则表,
-- id:主键,name:规则唯一标识, title:规则中文名称 status 状态:为1正常,为0禁用,condition:规则表达式,为空表示存在就验证,不为空表示按照条件验证
-- ----------------------------
DROP TABLE IF EXISTS `hlz_auth_rule`;
CREATE TABLE `hlz_auth_rule` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` char(80) NOT NULL DEFAULT '',
`title` char(20) NOT NULL DEFAULT '',
`type` tinyint(1) NOT NULL DEFAULT '1',
`status` tinyint(1) NOT NULL DEFAULT '1',
`condition` char(100) NOT NULL DEFAULT '', # 规则附件条件,满足附加条件的规则,才认为是有效的规则
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- hlz_auth_group 用户组表,
-- id:主键, title:用户组中文名称, rules:用户组拥有的规则id, 多个规则","隔开,status 状态:为1正常,为0禁用
-- ----------------------------
DROP TABLE IF EXISTS `hlz_auth_group`;
CREATE TABLE `hlz_auth_group` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`title` char(100) NOT NULL DEFAULT '',
`status` tinyint(1) NOT NULL DEFAULT '1',
`rules` char(80) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- hlz_auth_group_access 用户组明细表
-- uid:用户id,group_id:用户组id
-- ----------------------------
DROP TABLE IF EXISTS `hlz_auth_group_access`;
CREATE TABLE `hlz_auth_group_access` (
`uid` mediumint(8) unsigned NOT NULL,
`group_id` mediumint(8) unsigned NOT NULL,
UNIQUE KEY `uid_group_id` (`uid`,`group_id`),
KEY `uid` (`uid`),
KEY `group_id` (`group_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
################数据库操作--复制结束################
/**
* 检查权限
* @param name string|array 需要验证的规则列表,支持逗号分隔的权限规则或索引数组
* @param uid int 认证用户的id
* @param string mode 执行check的模式
* @param relation string 如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
* @return boolean 通过验证返回true;失败返回false
*/
/*
* 满足条件,则输出相应结果
* @param String : rule 要验证的规则名称,一般是“模块名/控制器名/方法”
* @param any : true 符合规则后,执行的代码
* @param String : false 不符合规则的,执行代码,默认为抛出字符串‘’
* @param String : relation 默认值为‘or’,表示有一条规则满足条件即可,‘and’表示所有规则都得满足
* @return String : 对应true或者false情况,输出的值
*/
function auth_check($rule, $true, $false='', $relation='or'){
// 如果是超级管理员,默认通过验证
if( isset($_SESSION['staff']['super']) ){
return $true;
}else{
$uid = 0 ; // 用户的id,来自登陆时,记录的职员的session,如果没有则默认为0
$auth = new \Mine\Auth();
if( isset($_SESSION['staff']['id']) ){
$uid = $_SESSION['staff']['id'];
}
return $auth->check($rule, $uid, 1, 'url', $relation) ? $true : $false ;
}
}
<!-- 商品管理,权限控制-->{:auth_check('con/Admin/goods','
<li class="layui-nav-item layui-nav-itemed">
<a href="javascript:;">商品管理</a>
<dl class="layui-nav-child">
<dd id="goods_categroy">
<a href="/Admin/goods_categroy">分类</a></dd>
<dd id="goods_goods">
<a href="/Admin/goods_goods">总览</a></dd>
</dl>
</li>')}
/**
* 管理员块,节点访问权限控制
* @param String : rule 要验证的规则名称,一般是“模块名(这里三位缩写)/控制器名/方法”[英文全小写] ,示例 con/Admin/hall
* @return Void 没有权限,则退出程序
*/
function node_check( $rule){
$msg['Err'] = 1002;
$rule = strtolower($rule);
// 如果不是管理员
if( !isset( $_SESSION['staff']['id'] ) ){
if( preg_match('/^con/i', $rule) ){ // 管理员登陆超时,用这个
header('Location:/Admin'); exit();
}
exit( json_encode($msg) );
}
$uid = $_SESSION['staff']['id'] ;
$auth= new \Mine\Auth();
// 如果既没有普通权限,又不是超级管理员
if( !$auth->check($rule, $uid) && !isset($_SESSION['staff']['super']) ){
// 如果是controller,则重定向
if( preg_match('/^con/i', $rule) ){
header('Location:/Admin'); exit();
}else{
exit( json_encode($msg) );
}
}
}
// 示例:检查是否能访问 /con/Admin/hall
node_check('/con/Admin/hall');
评论列表点此评论