我的一个新rbac的实现草案

<<采用mixin原理实现的rbac解决方案>>

作者:axgle

功能特征(write less,do more):

1.支持一个用户扮演多个角色

2.角色可以继承,可以包含其他角色

3.支持task,task就像角色一样

4.支持business rule(业务规则)

5.支持统一的operation名称检查(例如master的edit和author的edit,edit名称相同,但业务规则不同,author只能编辑自己的,但权限检查的时候依然用"edit"这个名称).

实现原理:

用户与AuthItem之间的关系约定:

1.AuthItem的定义: 角色,task,operation,统称AuthItem

2.mixin原则: 任何AuthItem可以有多个Child与之关联(把Child AuthItem mixin到某个AuthItem)

3.单项分配原则: 一个用户只能有一个"直接"的AuthItem与之关联

根据以上约定,则自然一个用户可以有多个AuthItem与之"间接"关联(可以解决一个用户多个角色的问题).

1197

auth_rabc.png

检查用户是否具有某个操作权限,就是看该用户所属的AuthItem的层次关系是否连通.

形象的说,用户关联到一颗树的根节点,该根节点就是用户所属的AuthItem($name).首先检查根节点($name)的直接child中是否有待检查的目标($child),有就成功返回.没有就查找目标($child)的父节点,把该父节点当成新的目标,递归检查即可.如下采用Yii的数据库操作方法的演示:




function checkAccess($name,$child,$params=array()){

    $criteria=new CDbCriteria();

    $criteria->compare('name',$name);

    $criteria->compare('child',$child);

    $model=AuthChild::model()->find($criteria);

    //var_dump($model);

    if($model){

        if($model->rule){

            return eval($model->rule);

        }

        return true;

    }else{

        $criteria=new CDbCriteria();

        $criteria->compare('child',$child);

        $models=AuthChild::model()->findAll($criteria);

        foreach($models as $model){

            if(checkAccess($name,$model->name, $params)){ return true;}

        }

    }

    return false;

}


echo (int)checkAccess('author', 'editAsset',3);



auth_schema.sql




SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";


CREATE TABLE IF NOT EXISTS `auth_child` (

  `name` varchar(100) NOT NULL,

  `child` varchar(100) NOT NULL,

  `rule` text,

  UNIQUE KEY `name_UNIQUE` (`name`,`child`),

  KEY `fk_mixin_item` (`name`),

  KEY `fk_mixin_item1` (`child`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1;


INSERT INTO `auth_child` (`name`, `child`, `rule`) VALUES

('author', 'edit', 'return $params==3;'),

('author', 'view', NULL),

('edit', 'editAsset', NULL),

('edit', 'editCampaign', NULL),

('master', 'edit', NULL),

('master', 'view', NULL),

('viewer', 'view', NULL);


CREATE TABLE IF NOT EXISTS `auth_item` (

  `name` varchar(100) NOT NULL,

  `desc` text,

  PRIMARY KEY  (`name`),

  UNIQUE KEY `name_UNIQUE` (`name`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='desc';


INSERT INTO `auth_item` (`name`, `desc`) VALUES

('author', NULL),

('edit', NULL),

('editAsset', NULL),

('editCampaign', NULL),

('master', NULL),

('view', NULL),

('viewer', NULL);




ALTER TABLE `auth_child`

  ADD CONSTRAINT `fk_mixin_item` FOREIGN KEY (`name`) REFERENCES `auth_item` (`name`) ON DELETE CASCADE ON UPDATE CASCADE,

  ADD CONSTRAINT `fk_mixin_item1` FOREIGN KEY (`child`) REFERENCES `auth_item` (`name`) ON DELETE CASCADE ON UPDATE CASCADE;




匿名用户你打算是怎么授权的?

像rights module,它是在controller里面设置哪些可以直接访问action

像srbac module,它是用一个.php文件来保存那些可以直接访问的action

你做的会不会是这样,每个用户访问的时候,没有登录状态,自动给他一个登录(不过Yii默认给没登录的用户设为isGuest),我称为guest角色吧,然后将对guest的授权是保存在数据库里面。

是的.因为访问的时候,都是针对"某一个"用户的,这个用户一次只能有一个角色.那么所有的匿名用户,自然都是guest角色,可以给guest指派一些访问权限.

通常web应用里,都有用户表(user),添加一个role字段即可(因为一个用户只有一种直接角色).

没有登陆: Yii::app()->user->role=‘guest’

登陆用户: Yii::app()->user->role= $user->role

checkAccess的时候,用Yii::app()->user->role即可.

补充描述一下 单项分配原则: 一个用户只能有一个"直接"的AuthItem与之关联.

这类似于某用户是孙悟空,可以72变;另外一用户是猪八戒,可以36变.孙悟空只有一个,猪八戒也是,但依然可以扮演多个其他角色. B)

这是本方案简化权限体系的一个核心约定.