相信大家对 RBAC 权限控制都比较了解。我们来
下面是摘自 yii 权威指南中关于 RBAC 权限控制的介绍
基本概念
角色是 权限 的集合 (例如:建贴、改贴)。一个角色 可以指派给一个或者多个用户。要检查某用户是否有一个特定的权限, 系统会检查该包含该权限的角色是否指派给了该用户。
可以用一个规则 rule 与一个角色或者权限关联。一个规则用一段代码代表, 规则的执行是在检查一个用户是否满足这个角色或者权限时进行的。例如,"改帖" 的权限 可以使用一个检查该用户是否是帖子的创建者的规则。权限检查中,如果该用户 不是帖子创建者,那么他(她)将被认为不具有 "改帖"的权限。
角色和权限都可以按层次组织。特定情况下,一个角色可能由其他角色或权限构成, 而权限又由其他的权限构成。Yii 实现了所谓的 局部顺序 的层次结构,包含更多的特定的 树 的层次。 一个角色可以包含一个权限,反之则不行。(译者注:可理解为角色在上方,权限在下方,从上到下如果碰到权限那么再往下不能出现角色)
配置
知道概念之后我们可以开始配置我们 Yii 中关于 RBAC 的组件authManager
return [
// ...
'components' => [
'authManager' => [
'class' => 'yii\rbac\DbManager',
//'class'=>'yii\rbac\PhpManager',
],
// ...
],
];
这之中我们的 yii 给我们提供了两套授权方案
① DbManager
把授权数据存贮在数据库中
② PhpManager
使用 PHP 脚本存取授权数据
如果我们是一个小网站(意味着我们的角色和权限改动很小),我们应该选取 php 脚本存储
配置中的可选项
cache
=> 开启 RBAC 缓存,用于提高 RBAC 性能(如果没有设置则代表缓存没有开启)
cacheKey
=> 缓存的密钥(默认值 ‘rbac’ )
db
=> 数据库连接对象(默认值 db )
itemChildTable
指定存储 auth_item_child (存放权限或用户的子节点数据表) 的表名称 (默认值 ‘{{%auth_item}}’)(%表示表前缀)
ruleTable
同理存放规则名称数据库(默认值为 ‘{{%auth_rule}}’ )
assignmentTable
同理
itemTable
同理
注: 在 basic 模板下我们要在 config/web.php
和 config/console.php
中配置,在 advanced 中,只能在 common/config/main.php
中声明一次 (这段话是出自权威指南的上话,但笔者亲测在 advanced 模板中 backend 和 frontend 中都可以配置)
建立授权关系
在建立授权关系时,我们需要有以下 4 张表
itemTable
: 该表存放授权条目(译者注:即角色和权限)。默认表名为 “%auth_item” 。itemChildTable
: 该表存放授权条目的层次关系。默认表名为 “%auth_item_child”。assignmentTable
: 该表存放授权条目对用户的指派情况。默认表名为 ” %auth_assignment”。ruleTable
: 该表存放规则。默认表名为 “%auth_rule”。所以我们需要去数据库中建立上面 4 张表。
不过 yii 已经为我们建立了上面四张表的模板。我们可以用 @yii/rbac/migrations
目录中的数据库迁移文件来做这件事
在 yii 根目录下使用命令./yii migrate --migrationPath=@yii/rbac/migrations
(后面我会出一篇有关 yii 数据迁移的笔记)
执行完命令,我们四张表就建立完成了。我们就可以使用Yii::$app->authManager
来访问我们的 authManager 组件了
authManager 可用方法
addChild($parent,$child) //给该授权增加一个子项 (授权可用是规则,也可以是角色)
assign($role,$userId) //给用户分配一条权限或用户组
canAddChild($parent,$child)//检查能否将子节点添加到父节点中去。(返回 bool)
/*创建权限或者数据*/
createPermission($name)//返回一个权限规则的实例
createRole($name)//返回一个名字为 '$name' 的角色实例
add($object) //添加一个角色,权限,规则到 auth_item 表,$object 可以为上面几个 create 返回的方法
getChildren($name)//根据 name 查找它的子用户或者子权限
getRoles()//以数组的形式返回所有的角色
getPermissions()//返回所有的权限规则信息以数组的形式返回
removeChildren($parent)//把该父类的全部子节点的依赖关系删除
removeChild($parent,$child)//删除指定的子节点和父节点的依赖关系
remvokeAll($uid)//解除 用户-用户组 的关系
getAssignments($uid)//获取所有的用户权限
getPermissionsByUser($userId)//返回该用户所有的规则
getRolesByUser($userId)//返回该用户对应的角色。
添加我们的角色
我们随便添加一条
$auth = Yii::$app->authManager; //获取我们的 authManager 组件
$obj = $auth->createRole(' 普通管理员 ');//添加角色名称
$obj->description = ' 没有实权的管理 ';//添加角色描述
$auth -> add($obj);
然后我们就可以在数据库中看到我们的插入的数据了
当然,如果我们看他不爽,我们也是可以把它删除的。
$obj = $auth->createRole(' 普通管理员 ');//添加角色名称
$auth -> remove($obj);//删除该管理
为该角色分配权限
$auth->assign($obj,$adminUid);//把我们$obj 角色分配给$uid 用户
其中 obj是我们上面创建的角色, o b j 是 我 们 上 面 创 建 的 角 色 , adminUid 是分配的用户 id
创建我们的规则
$obj = $auth->createPermission('category/del');//创建分类删除功能
$auth->add($obj);
将我们的规则添加到用户组下
$auth->addChild($auth->getRole(' 分类管理员 '),$obj)//将我们上面创建的分类删除权限分配给分类管理员
我们一个简单的 RBAC 创建好了,现在我们开启我们的认证.
①简单的在 ACF 中验证静态
//我们在控制器下的 behavious 写下我们的访问限制
public function behaviors()
{
return [
// 访问过滤控制器
'access' => [
'class' => AccessControl::className(),
'only' => ['add', 'delete', 'update', 'select'],
'rules' => [
// category' 角色的访问授权
[
'allow' => true,//允许我们
'actions' => ['del'],
'roles' => ['category'],
],
],
],
];
这种验证方式,如果我们需要改动,我们需要改动很多地方。例如我们要取消分类管理员的删除分类的权限,就很麻烦。
所以我们引入了动态验证
②动态的授权管理
这个和我们静态验证的区别是,我们可以根据数据库中的角色,来动态管理该授权
代码实例
class BaseController extends Controller
{
public function beforeAction($action)
{
if(!parent::beforeAction($action))
{
return false;//如果父类验证失败,则返回失败
}
$permission = $action->controller->module->requestedRoute;//记录我们访问的规则名称
if(Yii::$app->user->can($permission))
{
return true;//如该用户能访问该请求,则进行返回
}
throw new UnauthorizedHttpException(' 你没有该权限 ');//如果没有该权限,抛出一个异常
}
}
我们下面只需要在我们需要限制访问的控制器中继承该方法即可。
如果我们之中需要做到文章管理员只能删除自己创建的文章,不能删除其他人创建的文章,我们如何做到对他的权限判断呢?
Yii 为我们提供了一套精准的判断方法
使用 rules 精准认证每一条数据
class AuthorRule extends Rule
{
public $name = 'isAuthor';
public function execute($user, $item, $params)
{
$action = \Yii::$app->controller->action->id;//获取当前的动作名称
if ($action=='delete')//如果该动作为删除则验证是否能够删除
{
$article = Article::findOne(\Yii::$app->request->get('id'));
$author = $article->userid;
if ($author==\Yii::$app->user->id)
{
return true;
}
return false;
}
}
}
控制器中的方法
public function actionCreaterule()
{
if (\Yii::$app->request->isPost)
{
$name = \Yii::$app->request->post('class_name');
$class = 'common\models\\'.$name;
if (!class_exists($class))
{
throw new NotFoundHttpException('该规则类不存在');
}
$rule = new $class;
if (\Yii::$app->authManager->add($rule))
{
\Yii::$app->session->setFlash('info','添加成功');
}
}
return $this->render('createrule');
}
这样在我们为角色分配了权限之后,访问的时候,自动执行我们的方法