1. 名为 'isAuthor'
的规则到底是干什么的?
(1) 作用
- 动态权限判定:
'isAuthor'
规则用于判断当前用户是否是某个对象(如文章)的创建者。- 它通过检查上下文参数(如文章的
created_by
属性)来实现动态权限控制。
(2) 使用场景
-
文章管理:
- 示例:
- 只有文章的作者才能修改或删除自己的文章。
- 示例:
-
订单管理:
- 示例:
- 用户只能查看或编辑自己创建的订单。
- 示例:
-
部门审批:
- 示例:
- 部门经理只能审批本部门的报销单。
- 示例:
2. 规则内容具体是什么?
以下是一个典型的 'isAuthor'
规则的实现:
<?php
namespace app\rbac;
use yii\rbac\Rule;
/**
* AuthorRule 类用于检查当前用户是否是文章的作者。
*/
class AuthorRule extends Rule
{
// 定义规则的名称
public $name = 'isAuthor';
/**
* execute 方法用于实现动态权限检查。
* @param int|string $user 用户 ID,表示当前用户。
* @param Item $item 权限或角色对象,表示当前检查的权限或角色。
* @param array $params 传递的上下文参数,包含与权限判定相关的信息。
* @return bool 返回 true 表示满足规则,返回 false 表示不满足规则。
*/
public function execute($user, $item, $params)
{
// 检查 $params 数组中是否存在键名为 'post' 的元素
// 作用:确保传递的上下文参数中包含了文章对象(或类似的数据结构)。
// 原因:如果没有传递 'post' 参数,直接访问 $params['post'] 会导致错误。
// 知识点:PHP 的 isset() 函数,用于检查变量是否已设置且非 null。
if (!isset($params['post'])) {
return false;
}
// 获取 $params['post'] 对象的 created_by 属性
// 作用:获取文章的创建者 ID,用于与当前用户的 ID 进行比较。
// 原因:规则的核心逻辑是判断当前用户是否是文章的创建者。
// 知识点:PHP 的对象属性访问语法($object->property)。
$postCreatedBy = $params['post']->created_by;
// 判断文章的创建者 ID 是否等于当前用户的 ID
// 作用:验证当前用户是否是文章的创建者。
// 原因:只有文章的创建者才能满足规则条件。
// 知识点:PHP 的比较运算符(==),用于判断两个值是否相等。
return $postCreatedBy == $user;
}
}
3. 底层原理
(1) 数据存储
-
auth_rule
表结构:CREATE TABLE auth_rule ( name VARCHAR(64) NOT NULL PRIMARY KEY, -- 规则名称 data TEXT, -- 规则对象序列化后的数据 created_at INTEGER, -- 创建时间戳 updated_at INTEGER -- 更新时间戳 );
-
字段说明:
name
:规则的唯一标识符(如'isAuthor'
)。data
:规则对象序列化后的数据(通常是 PHP 对象)。
(2) 程序流
当调用 $auth->checkAccess($userId, $permissionName, $params)
时,系统会执行以下步骤:
-
加载权限信息:
- 从
auth_item
表中加载目标权限的元信息。
- 从
-
检查规则绑定:
- 如果权限绑定了规则(
rule_name
字段非空),从auth_rule
表中加载对应的规则。
- 如果权限绑定了规则(
-
反序列化规则:
- 将
auth_rule
表中的data
字段反序列化为 PHP 对象。
- 将
-
调用规则逻辑:
- 调用规则对象的
execute()
方法,并传递用户 ID、权限对象和上下文参数。
- 调用规则对象的
-
返回结果:
- 根据
execute()
方法的返回值决定是否授予权限。
- 根据
(3) 数据流
-
写入数据:
- 当将规则添加到 RBAC 系统时,规则对象会被序列化并存储到
auth_rule
表中。
- 当将规则添加到 RBAC 系统时,规则对象会被序列化并存储到
-
读取数据:
- 当调用
$auth->checkAccess()
时,规则对象会被从auth_rule
表中加载并反序列化。
- 当调用
4. 示例代码及详细注释
以下是一个完整的示例,展示如何使用 'isAuthor'
规则并附上详细注释。
<?php
namespace app\rbac;
use yii\rbac\Rule;
/**
* AuthorRule 类用于检查当前用户是否是文章的作者。
*/
class AuthorRule extends Rule
{
// 定义规则的名称
public $name = 'isAuthor';
/**
* execute 方法用于实现动态权限检查。
* @param int|string $user 用户 ID,表示当前用户。
* @param Item $item 权限或角色对象,表示当前检查的权限或角色。
* @param array $params 传递的上下文参数,包含与权限判定相关的信息。
* @return bool 返回 true 表示满足规则,返回 false 表示不满足规则。
*/
public function execute($user, $item, $params)
{
// 检查 $params 数组中是否存在键名为 'post' 的元素
if (!isset($params['post'])) {
return false;
}
// 获取 $params['post'] 对象的 created_by 属性
$postCreatedBy = $params['post']->created_by;
// 判断文章的创建者 ID 是否等于当前用户的 ID
return $postCreatedBy == $user;
}
}
// 获取 authManager 组件
// 作用:从 Yii2 应用中获取 RBAC 系统的管理器组件。
// 原因:authManager 是 Yii2 提供的 RBAC 核心组件,负责管理角色、权限和规则。
// 知识点:Yii2 的服务定位器机制,通过 \Yii::$app 访问应用组件。
$auth = \Yii::$app->authManager;
// 创建规则对象
// 作用:实例化 AuthorRule 类,用于定义动态权限检查逻辑。
// 原因:AuthorRule 是一个自定义规则,用于判断用户是否是文章的作者。
// 知识点:PHP 的类实例化语法(new 关键字)。
$rule = new \app\rbac\AuthorRule();
// 添加规则到 RBAC 系统
// 作用:将规则对象存储到 RBAC 系统中,以便后续使用。
// 原因:只有将规则添加到 RBAC 系统中,才能在权限检查时调用其逻辑。
// 知识点:Yii2 的 addRule() 方法,用于将规则存储到数据库中。
$auth->addRule($rule);
// 创建权限对象
// 作用:定义一个名为 "update-own-post" 的权限,表示更新自己文章的操作。
// 原因:权限是 RBAC 系统的基本单元,用于描述用户可以执行的操作。
// 知识点:Yii2 的 createPermission() 方法,用于创建权限对象。
$permission1 = $auth->createPermission('update-own-post');
// 设置权限描述
// 作用:为权限对象添加描述信息,便于理解和管理。
// 原因:描述信息可以帮助开发者和管理员快速了解权限的作用。
// 知识点:PHP 的属性赋值语法。
$permission1->description = 'Update own post';
// 绑定规则
// 作用:将规则 "isAuthor" 绑定到权限 "update-own-post"。
// 原因:通过规则可以实现动态权限检查,例如判断用户是否是文章的作者。
// 知识点:Yii2 的 rule_name 字段用于存储规则名称。
$permission1->ruleName = 'isAuthor';
// 将权限添加到 RBAC 系统
// 作用:将权限对象存储到 RBAC 系统中,以便后续使用。
// 原因:只有将权限添加到 RBAC 系统中,才能在权限检查时使用。
// 知识点:Yii2 的 add() 方法,用于将权限存储到数据库中。
$auth->add($permission1);
// 检查用户权限
// 作用:检查用户 ID 为 1 的用户是否拥有 "update-own-post" 权限。
// 原因:通过权限检查,可以动态控制用户的操作权限。
// 知识点:Yii2 的 checkAccess() 方法,用于判断用户是否拥有指定权限。
$post = new \stdClass();
$post->created_by = 1; // 假设文章的创建者是用户 ID 为 1 的用户
$params = ['post' => $post];
if ($auth->checkAccess(1, 'update-own-post', $params)) {
echo "用户可以更新自己的文章";
} else {
echo "用户无权更新文章";
}
5. 注意事项
(1) 上下文参数的重要性
$params
必须包含与权限判定相关的动态数据。- 示例:
$post = Post::findOne(1); // 获取文章对象 $params = ['post' => $post];
(2) 性能优化
- 规则的
execute()
方法会在每次权限检查时被调用。 - 避免在规则中执行耗时的操作(如复杂的数据库查询)。
(3) 缓存清理
- 如果启用了缓存功能,在添加或修改规则后需要清理缓存以确保最新的规则生效。
6. 总结
-
作用:
- 判断当前用户是否是某个对象的创建者(如文章的作者)。
-
使用场景:
- 动态权限判定。
- 细粒度权限控制。
- 规则复用。
-
底层原理:
- 数据存储在
auth_rule
表中。 - 规则对象被序列化后存储。
- 权限检查时加载并反序列化规则。
- 数据存储在
-
程序流和数据流:
- 写入数据:规则对象被序列化并存储到
auth_rule
表中。 - 读取数据:规则对象被从
auth_rule
表中加载并反序列化。
- 写入数据:规则对象被序列化并存储到