[转]Yii权限控制

基于角色的访问控制(Role-Based Access Control)

基于角色的访问控制提供了一种简单而又强大的集中访问控制。请参阅维基文章了解更多详细的RBAC与其他较传统的访问控制模式的比较。

Yii 通过其 authManager 组件实现了分等级的 RBAC 结构。在下文中,我们将首先介绍在此结构中用到的主要概念。然后讲解怎样定义用于授权的数据。在最后,我们看看如何利用这些授权数据执行访问检查。

概览(Overview)

在 Yii 的 RBAC 中,一个基本的概念是 授权项目(authorization item)。一个授权项目就是一个做某件事的许可(例如新帖发布,用户管理)。根据其粒度和目标受众,授权项目可分为 操作(operations),任务(tasks) 和 角色(roles)。一个角色由若干任务组成,一个任务由若干操作组成, 而一个操作就是一个许可,不可再分。例如,我们有一个系统,它有一个 管理员 角色,它由 帖子管理 和 用户管理 任务组成。 用户管理 任务可以包含 创建用户,修改用户 和 删除用户 操作组成。为保持灵活性,Yii 还允许一个角色包含其他角色或操作,一个任务可以包含其他操作,一个操作可以包括其他操作。

授权项目是通过它的名字唯一识别的。

一个授权项目可能与一个 业务规则 关联。业务规则是一段 PHP 代码,在进行涉及授权项目的访问检查时将会被执行。仅在执行返回 true 时,用户才会被视为拥有此授权项目所代表的权限许可。例如,当定义一个 updatePost(更新帖子) 操作时,我们可以添加一个检查当前用户 ID 是否与此帖子的作者 ID 相同的业务规则,这样,只有作者自己才有更新帖子的权限。

通过授权项目,我们可以构建一个 授权等级体系 。在等级体系中,如果项目 A 由另外的项目 B 组成(或者说 A 继承了 B 所代表的权限),则 A 就是 B 的父项目。一个授权项目可以有多个子项目,也可以有多个父项目。因此,授权等级体系是一个偏序图(partial-order graph)结构而不是一种树状结构。在这种等级体系中,角色项目位于最顶层,操作项目位于最底层,而任务项目位于两者之间。

一旦有了授权等级体系,我们就可以将此体系中的角色分配给用户。而一个用户一旦被赋予一个角色,他就会拥有此角色所代表的权限。例如,如果我们赋予一个用户 管理员 的角色,他就会拥有管理员的权限,包括 帖子管理 和 用户管理 (以及相应的操作,例如 创建用户)。

现在有趣的部分开始了,在一个控制器动作中,我们想检查当前用户是否可以删除指定的帖子。利用 RBAC 等级体系和分配,可以很容易做到这一点。如下:

view plaincopy
if(Yii::app()->user->checkAccess(‘deletePost’))
{
// 删除此帖
}

配置授权管理器(Authorization Manager)

在我们准备定义一个授权等级体系并执行访问权限检查之前,我们需要配置一下 authManager 应用组件。 Yii 提供了两种授权管理器: CPhpAuthManager 和 CDbAuthManager。前者将授权数据存储在一个 PHP 脚本文件中而后者存储在数据库中。配置 authManager 应用组件时,我们需要指定使用哪个授权管理器组件类,以及所选授权管理器组件的初始化属性值。例如:

view plaincopy
return array(
‘components’=>array(
‘db’=>array(
‘class’=>’CDbConnection’,
‘connectionString’=>’sqlite:path/to/file.db’,
),
‘authManager’=>array(
‘class’=>’CDbAuthManager’,
‘connectionID’=>’db’,
),
),
);

然后,我们便可以使用 Yii::app()->authManager 访问 authManager 应用组件。

定义授权等级体系

定义授权等级体总共分三步:定义授权项目,建立授权项目之间的关系,还要分配角色给用户。 authManager 应用组件提供了用于完成这三项任务的一系列 API 。

要定义一个授权项目,可调用下列方法之一,具体取决于项目的类型:

CAuthManager::createRole
CAuthManager::createTask
CAuthManager::createOperation
建立授权项目之后,我们就可以调用下列方法建立授权项目之间的关系:

CAuthManager::addItemChild
CAuthManager::removeItemChild
CAuthItem::addChild
CAuthItem::removeChild
最后,我们调用下列方法将角色分配给用户。

CAuthManager::assign
CAuthManager::revoke
下面的代码演示了使用 Yii 提供的 API 构建一个授权体系的例子:

view plaincopy
$auth=Yii::app()->authManager;

$auth->createOperation(‘createPost’,’create a post’);
$auth->createOperation(‘readPost’,’read a post’);
$auth->createOperation(‘updatePost’,’update a post’);
$auth->createOperation(‘deletePost’,’delete a post’);

$bizRule=’return Yii::app()->user->id==$params[“post”]->authID;’;
$task=$auth->createTask(‘updateOwnPost’,’update a post by author himself’,$bizRule);
$task->addChild(‘updatePost’);

$role=$auth->createRole(‘reader’);
$role->addChild(‘readPost’);

$role=$auth->createRole(‘author’);
$role->addChild(‘reader’);
$role->addChild(‘createPost’);
$role->addChild(‘updateOwnPost’);

$role=$auth->createRole(‘editor’);
$role->addChild(‘reader’);
$role->addChild(‘updatePost’);

$role=$auth->createRole(‘admin’);
$role->addChild(‘editor’);
$role->addChild(‘author’);
$role->addChild(‘deletePost’);

$auth->assign(‘reader’,’readerA’);
$auth->assign(‘author’,’authorB’);
$auth->assign(‘editor’,’editorC’);
$auth->assign(‘admin’,’adminD’);

建立此授权等级体系后,authManager 组件(例如 CPhpAuthManager, CDbAuthManager)就会自动加载授权项目。因此,我们只需要运行上述代码一次,并不需要在每个请求中都要运行。

信息: 上面的示例看起来比较冗长拖沓,它主要用于演示的目的。 开发者通常需要开发一些用于管理的用户界面,这样最终用户可以通过界面更直观地建立一个授权等级体系。

使用业务规则

在定义授权等级体系时,我们可以将 业务规则 关联到一个角色,一个任务,或者一个操作。我们也可以在为一个用户分配角色时关联一个业务规则。一个业务规则就是一段 PHP 代码,在我们执行权限检查时被执行。代码返回的值用来决定是否将角色或分配应用到当前用户。在上面的例子中,我们把一条业务规则关联到了 updateOwnPost 任务。在业务规则中,我们简单的检查了当前用户的 ID 是否与指定帖子的作者 ID 相同。 $params 数组中的帖子(post)信息由开发者在执行权限检查时提供。

权限检查

要执行权限检查,我们首先需要知道授权项目的名字。例如,要检查当前用户是否可以创建帖子,我们需要检查他是否拥有 createPost 所表示的权限。然后我们调用 CWebUser::checkAccess 执行权限检查:

view plaincopy
if(Yii::app()->user->checkAccess(‘createPost’))
{
// 创建帖子
}

如果授权规则关联了一条需要额外参数的业务规则,我们也可以传递给它。例如,要检查一个用户是否可以更新帖子,我们可以通过 $params 传递帖子的数据:

view plaincopy
$params=array(‘post’=>$post);
if(Yii::app()->user->checkAccess(‘updateOwnPost’,$params))
{
// 更新帖子
}

使用默认角色

注意: 默认角色功能从 1.0.3 版本起可用。

许多 Web 程序需要一些可以分配给系统中所有或大多数用户的比较特殊的角色。例如,我们可能想要分配一些权限给所有已通过身份验证的用户。如果我们特意指定并存储这些角色分配,就会引起很多维护上的麻烦。我们可以利用 默认角色 解决这个问题。

默认角色就是一个隐式分配给每个用户的角色,这些用户包括通过身份验证的用户和游客。我们不需要显式地将其分配给一个用户。当 CWebUser::checkAccess 被调用时,将会首先检查默认的角色,就像它已经被分配给这个用户一样。

默认角色必须定义在 CAuthManager::defaultRoles 属性中。例如,下面的配置声明了两个角色为默认角色:authenticated 和 guest。

view plaincopy
return array(
‘components’=>array(
‘authManager’=>array(
‘class’=>’CDbAuthManager’,
‘defaultRoles’=>array(‘authenticated’, ‘guest’),
),
),
);

由于默认角色会被分配给每个用户,它通常需要关联一个业务规则以确定角色是否真的要应用到用户。例如,下面的代码定义了两个角色, authenticated 和 guest,很高效地分别应用到了已通过身份验证的用户和游客用户。

view plaincopy
$bizRule=’return !Yii::app()->user->isGuest;’;
$auth->createRole(‘authenticated’, ‘authenticated user’, $bizRule);

$bizRule=’return Yii::app()->user->isGuest;’;
$auth->createRole(‘guest’, ‘guest user’, $bizRule);

发表评论

电子邮件地址不会被公开。 必填项已用*标注


*