在 Yii2 中,需要判断当前登录用户是否具体接口访问权限(基于 RBAC、默认角色)
1、当前的权限判断,是在控制器方法中实现如下
$conventionId = $this->request->post('convention_id', '');
$convention = Convention::find()->where([
'id' => $conventionId
])->limit(1)->one();
if (!$convention) {
return [
'code' => 10403,
'message' => '大会不存在!',
];
}
$mapping = CompanyEmployeeMapping::find()->where([
'user_id' => Yii::$app->user->id,
'company_id' => $convention->company_id,
])->limit(1)->one();
if (!$mapping) {
//判断是否为联络员
$contact = ConventionContact::find()->where('convention_id = :conventionId AND (user_id = :userId OR phone = :phone)', [
':conventionId' => $conventionId,
':userId' => Yii::$app->user->id,
':phone' => Yii::$app->user->identity->pure_phone_number,
])->limit(1)->one();
//判断是否为签到管理员
$checkinManager = ConventionCheckinManager::find()->where('convention_id = :conventionId AND (user_id = :userId OR phone = :phone)', [
':conventionId' => $conventionId,
':userId' => Yii::$app->user->id,
':phone' => Yii::$app->user->identity->pure_phone_number,
])->limit(1)->one();
if (!$contact && !$checkinManager) {
return [
'code' => 10001,
'message' => '您没有数据权限',
];
}
}
SELECT * FROM `conventions` WHERE `id`='1826937119386051' LIMIT 1 SELECT * FROM `company_employee_mapping` WHERE (`user_id`='1826937119386043') AND (`company_id`='1826937119386040') LIMIT 1 SELECT * FROM `convention_contacts` WHERE convention_id = '1826937119386051' AND (user_id = '1826937119386043' OR phone = '13980074657') LIMIT 1 SELECT * FROM `convention_checkin_managers` WHERE convention_id = '1826937119386051' AND (user_id = '1826937119386043' OR phone = '13980074657') LIMIT 1
2、计划基于 RBAC 实现,避免在每个控制器方法中重复复制(即使提炼出一个公共的方法,也不够灵活)
3、 创建自定义规则类 在 common/rbac/ 目录下创建以下规则类:
CompanyEmployeeRule.php
<?php
namespace common\rbac;
use yii\rbac\Item;
use yii\rbac\Rule;
use common\models\CompanyEmployeeMapping;
/**
* 检查 user_id 是否和通过参数传进来的 user 参数相符
*/
class CompanyEmployeeRule extends Rule
{
public $name = 'isCompanyEmployee';
/**
* @param string|integer $user 用户 ID.
* @param Item $item 该规则相关的角色或者权限
* @param array $params 传给 ManagerInterface::checkAccess() 的参数
* @return boolean 代表该规则相关的角色或者权限是否被允许
*/
public function execute($user, $item, $params): bool
{
if (!isset($params['convention'])) {
return false;
}
return CompanyEmployeeMapping::find()
->where([
'user_id' => $user,
'company_id' => $params['convention']->company_id,
])
->exists();
}
}
ConventionContactRule.php
<?php
namespace common\rbac;
use common\models\User;
use yii\rbac\Item;
use yii\rbac\Rule;
use common\models\ConventionContact;
/**
* 检查 user_id 是否和通过参数传进来的 user 参数相符
*/
class ConventionContactRule extends Rule
{
public $name = 'isConventionContact';
/**
* @param string|integer $user 用户 ID.
* @param Item $item 该规则相关的角色或者权限
* @param array $params 传给 ManagerInterface::checkAccess() 的参数
* @return boolean 代表该规则相关的角色或者权限是否被允许
*/
public function execute($user, $item, $params): bool
{
if (!isset($params['convention'])) {
return false;
}
$userModel = User::findOne($user);
return ConventionContact::find()
->where([
'convention_id' => $params['convention']->id,
'user_id' => $user,
'phone' => $userModel->pure_phone_number,
])->exists();
}
}
CheckinManagerRule.php
<?php
namespace common\rbac;
use common\models\User;
use yii\rbac\Item;
use yii\rbac\Rule;
use common\models\ConventionCheckinManager;
/**
* 检查 user_id 是否和通过参数传进来的 user 参数相符
*/
class CheckinManagerRule extends Rule
{
public $name = 'isCompanyEmployee';
/**
* @param string|integer $user 用户 ID.
* @param Item $item 该规则相关的角色或者权限
* @param array $params 传给 ManagerInterface::checkAccess() 的参数
* @return boolean 代表该规则相关的角色或者权限是否被允许
*/
public function execute($user, $item, $params): bool
{
if (!isset($params['convention'])) {
return false;
}
$userModel = User::findOne($user);
return ConventionCheckinManager::find()
->where([
'convention_id' => $params['convention']->id,
'user_id' => $user,
'phone' => $userModel->pure_phone_number,
])->exists();
}
}
4、所谓默认角色就是 隐式 地指派给 所有 用户的角色。不需要调用 yii\rbac\ManagerInterface::assign() 方法做显示指派,并且授权数据中不包含指派信息。使用 ./yii migrate/create init_convention_rbac 创建新迁移,然后实现创建层次结构
<?php
use yii\db\Migration;
use common\rbac\CompanyEmployeeRule;
use common\rbac\ConventionContactRule;
use common\rbac\CheckinManagerRule;
use yii\base\Exception;
/**
* Class m250331_034538_init_convention_rbac
*/
class m250331_034538_init_convention_rbac extends Migration
{
/**
* @return void
* @throws Exception
*/
public function safeUp()
{
$auth = Yii::$app->authManager;
// 清除所有现有RBAC数据
$auth->removeAll();
// 创建自定义规则
$companyEmployeeRule = new CompanyEmployeeRule();
$auth->add($companyEmployeeRule);
$conventionContactRule = new ConventionContactRule();
$auth->add($conventionContactRule);
$checkinManagerRule = new CheckinManagerRule();
$auth->add($checkinManagerRule);
// 创建权限
$accessConvention = $auth->createPermission('accessConvention');
$accessConvention->description = '访问大会数据权限';
$auth->add($accessConvention);
// 创建角色并分配规则
$companyEmployee = $auth->createRole('companyEmployee');
$companyEmployee->ruleName = $companyEmployeeRule->name;
$auth->add($companyEmployee);
$auth->addChild($companyEmployee, $accessConvention);
$conventionContact = $auth->createRole('conventionContact');
$conventionContact->ruleName = $conventionContactRule->name;
$auth->add($conventionContact);
$auth->addChild($conventionContact, $accessConvention);
$checkinManager = $auth->createRole('checkinManager');
$checkinManager->ruleName = $checkinManagerRule->name;
$auth->add($checkinManager);
$auth->addChild($checkinManager, $accessConvention);
}
/**
* {@inheritdoc}
*/
public function safeDown()
{
echo "m250331_034538_init_convention_rbac cannot be reverted.\n";
return false;
}
/*
// Use up()/down() to run migration code without a transaction.
public function up()
{
}
public function down()
{
echo "m250331_034538_init_convention_rbac cannot be reverted.\n";
return false;
}
*/
}
5、现在角色有 3 个:companyEmployee、conventionContact、checkinManager,皆具有权限 accessConvention。且检查一个用户是否满足角色的规则已经定义完成。
6、下一步不计划手动指定用户的角色,而是基于默认角色,自动指定。参考:使用默认角色 https://www.yiiframework.com/doc/guide/2.0/zh-cn/security-authorization#using-default-roles 在配置 authManager 时指定 yii\rbac\BaseManager::$defaultRoles 选项 。如图1
return [
// ...
'components' => [
'authManager' => [
'class' => 'yii\rbac\DbManager',
// 'cache' => 'cache',
'defaultRoles' => ['companyEmployee', 'conventionContact', 'checkinManager'],
],
// ...
],
];
7、检查当前用户是否具有 accessConvention 权限。确认检查通过,具有 accessConvention 权限。通过 ‘can()’ 方法会检查角色和权限。用户拥有角色或其继承角色,符合预期。如图2
if (Yii::$app->user->can('accessConvention', ['convention' => $convention])) {
$roles = Yii::$app->authManager->getRolesByUser(Yii::$app->user->id);
print_r($roles);
}
if (Yii::$app->user->can('companyEmployee', ['convention' => $convention])) { // 'can()' 方法会检查角色和权限
echo '用户拥有 \'companyEmployee\' 角色或其继承角色';
}
if (Yii::$app->user->can('conventionContact', ['convention' => $convention])) { // 'can()' 方法会检查角色和权限
echo '用户拥有 \'conventionContact\' 角色或其继承角色';
}
if (Yii::$app->user->can('checkinManager', ['convention' => $convention])) { // 'can()' 方法会检查角色和权限
echo '用户拥有 \'checkinManager\' 角色或其继承角色';
}
SELECT * FROM `auth_assignment` WHERE `user_id`='1826937119386043' SELECT * FROM `auth_item` WHERE `name`='accessConvention' SELECT `parent` FROM `auth_item_child` WHERE `child`='accessConvention' SELECT * FROM `auth_item` WHERE `name`='checkinManager' SELECT `data` FROM `auth_rule` WHERE `name`='isCheckinManager' SELECT * FROM `users` WHERE `id`='1826937119386043' SELECT EXISTS(SELECT * FROM `convention_checkin_managers` WHERE (`convention_id`='1826937119386051') AND (`user_id`='1826937119386043') AND (`phone`='13980074657')) SELECT * FROM `auth_item` WHERE `name`='companyEmployee' SELECT `data` FROM `auth_rule` WHERE `name`='isCompanyEmployee' SELECT EXISTS(SELECT * FROM `company_employee_mapping` WHERE (`user_id`='1826937119386043') AND (`company_id`='1826937119386040')) SELECT `b`.* FROM `auth_assignment` `a`, `auth_item` `b` WHERE (`a`.`item_name`=`b`.`name`) AND (`a`.`user_id`='1826937119386043') AND (`b`.`type`=1)
8、检查当前用户是否具有 accessConvention 权限。确认检查不通过,无任何输出。不具有 accessConvention 权限。通过 ‘can()’ 方法会检查角色和权限。用户拥有角色或其继承角色,符合预期。如图3
SELECT * FROM `auth_assignment` WHERE `user_id`='1827082629726231' SELECT * FROM `users` WHERE `id`='1827082629726231' SELECT EXISTS(SELECT * FROM `convention_checkin_managers` WHERE (`convention_id`='1826937119386051') AND (`user_id`='1827082629726231') AND (`phone`='15609979522')) SELECT EXISTS(SELECT * FROM `company_employee_mapping` WHERE (`user_id`='1827082629726231') AND (`company_id`='1826937119386040')) SELECT * FROM `users` WHERE `id`='1827082629726231' SELECT EXISTS(SELECT * FROM `convention_contacts` WHERE (`convention_id`='1826937119386051') AND (`user_id`='1827082629726231') AND (`phone`='15609979522')) SELECT EXISTS(SELECT * FROM `company_employee_mapping` WHERE (`user_id`='1827082629726231') AND (`company_id`='1826937119386040')) SELECT * FROM `users` WHERE `id`='1827082629726231' SELECT EXISTS(SELECT * FROM `convention_contacts` WHERE (`convention_id`='1826937119386051') AND (`user_id`='1827082629726231') AND (`phone`='15609979522')) SELECT * FROM `users` WHERE `id`='1827082629726231' SELECT EXISTS(SELECT * FROM `convention_checkin_managers` WHERE (`convention_id`='1826937119386051') AND (`user_id`='1827082629726231') AND (`phone`='15609979522'))



1 条回复
[…] […]