ThinkPHP框架使用心得三 RBAC权限控制(2)简要原理

时间:2021-09-25 14:10:51

  上篇博文我将要描述了ThinkPHP提供的RBAC权限管理系统的使用方法,现在我大体描述一下它的基本实现原理,也就是RBAC类。这个类的结构如下:

class RBAC extends Think {
    static public function authenticate($map, $model = '') {}
    static function saveAccessList($authId = null) {}
    static function getRecordAccessList($authId = null, $module = '') {}
    static function checkAccess() {}
    static public function checkLogin() {}
    static public function AccessDecision($appName = APP_NAME) {}
    static public function getAccessList($authId) {}
    static public function getModuleAccessList($authId, $module) {}
}

  上篇博文讲到过,系统的一些不需要也不能认证的模块如登陆登出权限检测一类的操作放在一个公用模块中,如Public模块,系统初始登录时,无论从那个入口进入,会由于权限问题跳转到Public模块下,我们定义的登录页面,登录后到登录检测,跳转至首页(如果当前登录用户对首页没有操作权限就会一直来回跳)。

  上面从PublicAction到IndexAction其实经过了一个BaseAction,除了不需认证的模块,即这里的Public模块,其他模块都应该继承自BaseAction,他会自动执行一个方法_initialize()。这个方法调用rbac类库下的AccessDecision()。

  而AccessDecision()首先调用checkAccess()即向判断当前模块是否需要认证,这个过程就是看看是否定义了需要判断的模块,定义了看看当前模块是否在里面,在里面就不需要进行认证,没有就进行认证操作。或者看看是否定义了不需要认证的模块,定义了就看看当前模块是否在里面,在里面就进行认证,不在就不需要认证。而需要认证就返回true,不需要认证就返回false。这样好让下面的流程确定是否继续执行。

  我们只考虑需要认证的情况,且不使用管理员账号,因为系统检测到管理员账号就会不继续判断权限,这样就默认对任意模块都具有操作权限。当我们使用即时认证的模式,系统条用类库下的getAccessList()来获取权限列表。进行权限判断时会将当前用户的id作为参数创建方法中,然后首先根据这个用户id找到当前用户能操作的项目名和对应id,然后遍历得到的项目,从access表中获取能操作的每个项目下的模块名的模块id,再遍历每个模块得到能操作的方法id和方法名,将这些结果存储在权限列表数组下,得到的结果形如:

$access = array(
  '项目1' =>  array(
    '模块1' => array(
                '操作1' => '对应nodeid',
                '操作2' => '对应nodeid',
                 ...
                '操作j' => '对应nodeid', ),
    '模块2' => array(),
    ...
    '模块i' => array(),
  ),
  '项目2' => array(),
  ...
  '项目n' => array()
);             


这样的权限列表,其实这个数组存储的就是当前登录用户能够有权限操作的节点的id,我们对系统某个部分操作时一定是操作某个项目的某个模块的某个操作。我们只要判断当前操作是否在权限列表中就可以判断是否有权操作。

比如获取到的权限列表是:

array(1) {
  ["RBAC"] => array(1) {
    ["INDEX"] => array(3) {
      ["INDEX"] => string(1) "3"
      ["ADD"] => string(1) "4"
      ["EDIT"] => string(1) "5"
    }
  }
}
  意味着当前登录用户拥有RBAC-IndexAction下index,add,edit三个操作的使用权限,然后获取页面的操作位置:看看是否有值,有就认为有权限操作。
  这边还有可能产生一个思维混乱,那些不需认证的或者管理员账号,他们没有执行获取权限列表的操作,也就是说权限列表数组为空,不是出问题了么。至少我曾经纠结过这个问题,后来我突然发现,这就是南极企鹅跟北极熊打架谁厉害的问题。
根本没有关系。如果不需认证或者是管理员账号,不需要认证,等于去掉中间的代码不做退出的条件限制,都不退出了,代码当然一路执行下去,想干嘛干嘛了。
  以上将要介绍了rbac的思想,不过貌似还是没能完全脱离tp,框架用久了产生依赖性了,我打算回归原生代码重新整理一下基础知识了。
  有什么错误的地方,希望大神们可以不吝指正。谢谢。