TP中的两种权限设计

2017-01-13 10:52:24 PHP 1655 0

半年前,TP5.0发布了,它相对完整的文档出来了之后,云天河去通读了一次,感觉它更像Laraval了,更是察觉PHP框架目前正趋向于一个标准化,里面的带有的一些功能也是有异曲同工之处

这次主要讲讲Auth的实现过程

RBAC(Role-Based Access Control)

它是一种按web节点认证的方式,思想如下:

一个用户,可以对应多个用户组,
如果当前用户所在的角色组中,包含该节点,则有访问该节点的权限。
否则拒绝访问该节点。

Auth(Authentication)

其过程大致如下

Step1

接收 用户的id => uid

Step2

查询用户对应的规则字符串组,接着查询出所有的规则号 => array_merge

Step3

合并规则号时,数组键值去重 => array_unique

Step4

查询规则名称,若是选择认证url模式,则auth类会帮你把传入的$rule与所有规则名称转为小写,方便比较

Step5

情况1

若是配置的登陆时认证,会将规则列表的数组,存在session中,以后判断Auth的时候,会直接执行Step6

情况2

若是配置的实时认证,则每次都得查询数据库,并返回规则列表的数组

Step6

查询规则名称的数组中是否有对应的规则名 => 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'];
}

下载地址

Auth类

配置
// 默认配置
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;
################数据库操作--复制结束################
hlz_auth_group

hlz_auth_group_access

hlz_auth_rule

使用说明

\Mine\Auth()中的check()说明如下
/**
* 检查权限
* @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');
注:若无特殊说明,文章均为云天河原创,请尊重作者劳动成果,转载前请一定要注明出处