listenRain

  最近有点小忙,好久没有学习了。。。我忏悔。。。。

  RBAC英文全称Role-Based Access Control。即基于角色的权限控制。它的权限控制原理是将个项目-模块-操作的使用权限分配给角色组。然后将用户分到各用户组中,当然,一个用户可能有多个用户组。这样用户从属于用户组后就具有了该用户组的相关操作权限。ThinkPHP中有一个封装的很好的RBAC类库,十分好用的说。同时官方也提供的demo包中也有rbac的例子,不过,据说好多人看着头疼。我之前也拿这个例子来看,发现。。。超越了我的理解啊。。。。现在我对rbac的原理大体了解后来看它的demo,我知道问题所在了,它的demo写的太好。对于我这种刚学习的人而言,绝大部分的精力会不由自主的放进他的操作流程,而会忽略最重要的数据表之间的操作,从而很可能难以理解rbac的原理。

  我自己写了一个rbac的demo,最初的工作是利用curd编写一个对文章的增改查的程序,连用户登录都免了,简要代码:

1 class IndexAction extends Action {
2     public function index() {}  //文章列表
3     public function add() {}  //新增文章
4     public function edit() {}  //文章编辑
5     public function view() {}  //文章查看
6 }

实现的效果:

一个简单的系统搭建完成了,下面加入权限控制。

RBAC的实现至少需要五张数据表,(我使用tp默认的前缀think_)分别为:

thinkl_user 用户表
字段 类型 说明
id int(11)  pk
username varchar(50)  
password varchar(50)  

 

thinkl_access 权限表
字段 类型 说明
role_id smallint(6)  角色id
node_id smallint(6)  节点id
level tinyint  表示所属层次,项目=〉1,模块=〉2,操作=〉3
module varchar(50)  

 

thinkl_node 节点表
字段 类型 说明
id smallint(6)  pk
name varchar(20)  
title varchar(50)  
status tinyint  
remark varchar(255)  
sort smallint(6)  
pid smallint(6)  
level tinyint  

 

thinkl_role角色表
字段 类型 说明
id smallint(6)  pk
name varchar(20)  
pid smallint(6)  
status tinyint  
remark varchar(255)  

 

thinkl_role_user 角色用户关联表
字段 类型 说明
role_id smallint(6)  
user_id smallint(6)  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 RBAC认证流程图

rbac的原理其实就是这几张表的数据逻辑关系。我是手动建立相关数据,一遍数据建立下来,逻辑理清了,基本原理也能理解的不差了。

(一)建立用户表数据

建立三个用户,分别为system,admin,user1

(二)建立角色组

建立两个角色组,分别为admin,user,即管理组和普通组

(三)建立用户和用户组的关系

 将system,admin划归角色组1

将user1划归角色组2

这样组合用户的对应关系就建立好了

(4)建立节点表

所谓节点就是所有的项目、模块、操作的列表。这张表应该算rbac的核心。

我的demo中项目名rabc,有一个模块即IndexAction,下面还有index,add,edit,view四个操作。将这6条分别计入这张表中,注意pid的设置。同时level的值,1、2、3分别代表项目,模块,操作。

(5)建立权限表

对于权限的分配就在access表中。

表中数据的意思是role_id=1的组,即admin组具有操作节点1,2,3,4,6的权限,不具备操作节点5即rbac-Index-edit的权限。role_id=2的组即用户组织具有节点123的操作权限。

很重要的一点就是,权限的安排需要按层次来,即只有具备对项目的操作权限才能操作模块,同理,只有具备对项目-模块的操作权限才能操作下面的方法。

这样,rbac的操作从数据表层面来讲已经完成。下面对代码进行修改以完成rbac的权限控制。

 首先,将RBAC.class.php复制到项目目录Lib\Org下,也可以直接使用系统目录Lib\ORG\Util下的类库文件,只要能够import即可。

然后,在项目配置文件中定义rbac的相关配置项:

//rbac配置项
    \'USER_AUTH_ON\'              =>true,
    \'USER_AUTH_TYPE\'        =>2,        // 默认认证类型 1 登录认证 2 实时认证
    \'USER_AUTH_KEY\'             =>\'authId\',    // 用户认证SESSION标记
    \'ADMIN_AUTH_KEY\'        =>\'administrator\',
    \'USER_AUTH_MODEL\'           =>\'User\',    // 默认验证数据表模型
    \'AUTH_PWD_ENCODER\'          =>\'md5\',    // 用户认证密码加密方式
    \'USER_AUTH_GATEWAY\'         =>\'/Public/login\',// 默认认证网关
    \'NOT_AUTH_MODULE\'           =>\'Public\',    // 默认无需认证模块
    \'REQUIRE_AUTH_MODULE\'       =>\'\',        // 默认需要认证模块
    \'NOT_AUTH_ACTION\'           =>\'\',        // 默认无需认证操作
    \'REQUIRE_AUTH_ACTION\'       =>\'\',        // 默认需要认证操作
    \'GUEST_AUTH_ON\'             =>false,    // 是否开启游客授权访问
    \'GUEST_AUTH_ID\'             =>0,        // 游客的用户ID
    \'SHOW_RUN_TIME\'             =>true,        // 运行时间显示
    \'SHOW_ADV_TIME\'             =>true,        // 显示详细的运行时间
    \'SHOW_DB_TIMES\'             =>true,        // 显示数据库查询和写入次数
    \'SHOW_CACHE_TIMES\'          =>true,        // 显示缓存操作次数
    \'SHOW_USE_MEM\'              =>true,        // 显示内存开销
    \'DB_LIKE_FIELDS\'            =>\'title|remark\',
    \'RBAC_ROLE_TABLE\'           =>\'think_role\',
    \'RBAC_USER_TABLE\'           =>\'think_role_user\',
    \'RBAC_ACCESS_TABLE\'         =>\'think_access\',
    \'RBAC_NODE_TABLE\'           =>\'think_node\',

这些配置项可以直接从tp的rbacdemo中复制。每项的意思也基本都注明了。不需要说太多了。

再然后定义一个PublicAction用来放置一些不需要进行认证的模块。如果修改了配置项中NOT_AUTH_MODULE,那么就建立相应名称的action。这里面放置登录,登出,检验登录情况等操作。如果用户连登录都发现没有权限,这是个多么疯狂的情况,用户想登录一直说:你丫无权操作,一边凉快去。多抓狂。

代码结构:

class PublicAction extends Action{

    // 用户登录页面
    public function login() {
        if (!isset($_SESSION[C(\'USER_AUTH_KEY\')])) {
            $this->display();
        } else {
            $this->redirect(\'Index/index\');
        }
    }

    // 登录检测
    public function checkLogin() {
        
    }

    function loginout() {
        if (isset($_SESSION[C(\'USER_AUTH_KEY\')])) {
            unset($_SESSION[C(\'USER_AUTH_KEY\')]);
            unset($_SESSION);
            session_destroy();
            $this->assign("jumpUrl", __URL__ . \'/login/\');
            $this->success(\'登出成功!\');
        } else {
            $this->error(\'已经登出!\');
        }
    }

}

login,logout就是判断session时候存在。存在就认为已经登录,执行页面跳转或者删掉这个session以达到退出效果。

checklogin()是rbac的具体实现

public function checkLogin() {
        if (empty($_POST[\'username\'])) {
            $this->error(\'帐号错误!\');
        } elseif (empty($_POST[\'password\'])) {
            $this->error(\'密码必须!\');
        } 
        //生成认证条件
        $map = array();
        // 支持使用绑定帐号登录
        $map[\'username\'] = $_POST[\'username\'];
        import(\'ORG.Util.RBAC\');
        $authInfo = RBAC::authenticate($map);
        //使用用户名、密码和状态的方式进行认证
        if (false === $authInfo) {
            $this->error(\'帐号不存在或已禁用!\');
        } else {
            if ($authInfo[\'password\'] != md5($_POST[\'password\'])) {
                $this->error(\'密码错误!\');
            }
            $_SESSION[C(\'USER_AUTH_KEY\')] = $authInfo[\'id\'];
            if ($authInfo[\'username\'] == \'system\') {
                $_SESSION[\'administrator\'] = true;
            }
            
            // 缓存访问权限
            RBAC::saveAccessList();
            $this->success(\'登录成功!\');
        }
    }

首先判断提交过来的表单信息,然后引入rbac类,然后调用RBAC::authenticate($map);来获取认证信息。然后根据认证信息来判断用户时候登录成功以及具有的权限。

再然后编写一个BaseAction.class.php,这里放置一个自动方法,就是每次执行这个action时,这个方法会像构造函数一样自动执行。这个方法就是检查用户权限。

function _initialize() {
        // 用户权限检查
        if (C ( \'USER_AUTH_ON\' ) && !in_array(MODULE_NAME,explode(\',\',C(\'NOT_AUTH_MODULE\')))) {
            import ( \'@.Org.RBAC\' );
            if (! RBAC::AccessDecision ()) {
                //检查认证识别号
                if (! $_SESSION [C ( \'USER_AUTH_KEY\' )]) {
                    //跳转到认证网关
                    redirect ( PHP_FILE . C ( \'USER_AUTH_GATEWAY\' ) );
                }
                // 没有权限 抛出错误
                if (C ( \'RBAC_ERROR_PAGE\' )) {
                    // 定义权限错误页面
                    redirect ( C ( \'RBAC_ERROR_PAGE\' ) );
                } else {
                    if (C ( \'GUEST_AUTH_ON\' )) {
                        $this->assign ( \'jumpUrl\', PHP_FILE . C ( \'USER_AUTH_GATEWAY\' ) );
                    }
                    // 提示错误信息
                    $this->error ( L ( \'_VALID_ACCESS_\' ) );
                }
            }
        }
    }

然后修改IndexAction使它由Action改为继承至BaseAction,这样每个页面的执行都会执行自动方法。以后如果增加新的模块也让它继承BaseAction这样就实现了权限控制了。

以上简单的权限控制就完成了。代码基本可以从官方例子中复制稍作修改即可。下面看看效果。

 结果不太好表示,按之前对表的编辑,结合实际调试,使用system登录时,虽然他属于admin组,而admin组并不具备编辑的权限,但是由于它是系统管理员,判定具有所有权限。用admin登录可以发现只有编辑链接点击时无权操作。使用user1登录,除了能看首页,其他什么事不能干。

就此,RBAC算是结束了。至于官方的demo,是可以再页面上配置各种值,说白了就是将我的手动编辑表的过程在界面上实现。能够理解原理,下面就可以试着做出官方demo那样便捷的操作界面。

源代码,希望大神指正。

 

 

分类:

技术点:

相关文章:

  • 2022-02-08
  • 2022-02-05
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-07-14
  • 2022-12-23
  • 2022-01-08
  • 2022-12-23
  • 2022-12-23
  • 2021-12-27
  • 2021-06-13
相关资源
相似解决方案