管理权限的优势就是它很安全,不会被一些小BUG影响,导致这个网站或者这个软件混乱 ,生活里遇见问题个人比较喜欢用三W的方式去解决也就是'who what how',
首先是who:
权限管理规则
其次:what
权限管理里面我们需要明白管理权限的规则是什么:这个规则就是当前用户当前页面的当前地址
实现的原理是什么:原理很简单,就是我当前的规则在我的规则表里面是否存在
最后:how
怎么做可以分为两步:
one : 建立四个表,因为我们做什么得从实际出发,分析这个这个表里面需要什么
第一个表:这个表里储存当前的角色,因为我们后期所做的所有功能都是基于这个角色, 这个任意表满足三范式即可
第二个表:授权的规则表
第三个表:会员和授权表的管理变
第四个表:权限表,表里权限可以根据你需要的权限进行添加
two : 建好表以后我们就需要实现这个功能
/**
* 权限认证类
*
* 功能特性:
* 1,是对规则进行认证,不是对节点进行认证。用户可以把节点当作规则名称实现对节点进行认证。
* $auth=new Auth(); $auth->check('规则名称','用户id')
* 2,可以同时对多条规则进行认证,并设置多条规则的关系(or或者and)
* $auth=new Auth(); $auth->check('规则1,规则2','用户id','and')
* 第三个参数为and时表示,用户需要同时具有规则1和规则2的权限。 当第三个参数为or时,表示用户值需要具备其中一个条件即可。默认为or
* 3,一个用户可以属于多个用户组(think_auth_group_access表 定义了用户所属用户组)。我们需要设置每个用户组拥有哪些规则(think_auth_group 定义了用户组权限)
*
* 4,支持规则表达式。
* 在think_auth_rule 表中定义一条规则时,如果type为1, condition字段就可以定义规则表达式。 如定义{score}>5 and {score}<100 表示用户的分数在5-100之间时这条规则才会通过。
*
*/
protected $_config = array(
'AUTH_ON' => true, //认证开关
'AUTH_TYPE' => 1, // 认证方式,1为时时认证;2为登录认证。
'AUTH_GROUP' => 'think_auth_group', //用户组数据表名
'AUTH_GROUP_ACCESS' => 'think_auth_group_access', //用户组明细表
'AUTH_RULE' => 'think_auth_rule', //权限规则表
'AUTH_USER' => 'think_admin'//用户信息表
);
public function __construct() {
//先判断是否有配置文件的权限
if (config('AUTH_CONFIG')){
//可设置配置项 AUTH_CONFIG, 此配置项为数组。
$this->_config = array_merge($this->_config, config('AUTH_CONFIG'));
}
}
//获得权限$name 可以是字符串或数组或逗号分割, uid为 认证的用户id, $or 是否为or关系,为true是, name为数组,只要数组中有一个条件通过则通过,如果为false需要全部条件通过。
/**
* @ $name - 当前页面的地址(对应规则表的Name字段)
* @ $uid - 当前用户的ID
* @ $relation - 规则表达式:默认'or',判断$relation是否为空,不为空,就把$relation当成查询条件
*/
// $name = 'index/index/index,index/admin/save'
public function check($name, $uid, $relation='or') {
//1:判断是否开启权限验证
//功能作用
if (!$this->_config['AUTH_ON']){
return true;
}
//who开始
// 判断当前登陆用户拥有的权限 也就是地址
$name = strtolower($name);
//获取当前用户的所有权限
//2.获取当前用户组 所具有的全部权限
//$authList:
$authList = $this->getAuthList($uid);
if (is_string($name)) {
if (strpos($name, ',') !== false) {
$name = explode(',', $name);
} else {
$name = array($name);
}
}
//判断两个数组是否有相同的部分
//循环的去和数据库里面的节点表进行比较
//3.判断我需要认证的页面的权限是否在所有权限里面
$list = array(); //有权限的name
foreach ($authList as $val) {
if (in_array($val, $name))
$list[] = $val;
}
//4.判断第三步产生的一个或者多个权限的认证方式
if ($relation=='or' and !empty($list)) {
return true;
}
//获取需要验证的路径和当前用户又具有的所有权限中的路径
$diff = array_diff($name, $list);
//如果获取的数据库里的路径和当前的路径相等 则说明具有权限
if ($relation=='and' and empty($diff)) {
return true;
}
return false;
}
/**
* 获取用户的权限列表
*/
public function getAuthList($uid){
//定义一个空的静态的数组,可以像session一样保存数据
static $_authList = array();
//如果已经查过就直接返回查过的数据,否则就联表查
if (isset($_authList[$uid])) {
return $_authList[$uid];
}
//主要是针对2为登录认证的情况
if(isset($_SESSION['_AUTH_LIST_'.$uid])){
return $_SESSION['_AUTH_LIST_'.$uid];
}
//查用户所在组
$groups = $this->getGroups($uid);
//把roles字段里面的“1,2,2,2,2,3,4...”变成数组
$ids = array();
foreach ($groups as $g) {
//合并两个数组
$ids = array_merge($ids, explode(',', trim($g['rules'], ',')));
}
//去除重复的
$ids = array_unique($ids);
if (empty($ids)) {
$_authList[$uid] = array();
return array();
}
//通过$ids查rule表
$rules = DB::table($this->_config['AUTH_RULE'])->select(['id'=>array('in',$ids),'status'=>1]);
//循环规则,判断结果。
$authList = array();
foreach ($rules as $r) {
if (!empty($r['condition'])) {
//条件验证
$user = $this->getUserInfo($uid);
//把rule表里面的condition字段里面的{id}>2中{id}替换成$user['id']
$command = preg_replace('/\{(\w*?)\}/', '$user[\'\\1\']', $r['condition']);
//使用eval方来执行字符串语句,将结果保存到$condition里面
@(eval('$condition=(' . $command . ');'));
//如果$condition==true,就满足条件
if ($condition) {
$authList[] = strtolower($r['name']);
}
} else {
//存在就通过
$authList[] = strtolower($r['name']);
}
}
//将得到的结果保存到静态数组里面
$_authList[$uid] = $authList;
//如果验证方式是登录验证,就是保存到session里面
if($this->_config['AUTH_TYPE']==2){
//session结果
$_SESSION['_AUTH_LIST_'.$uid]=$authList;
}
return $authList;
}