BaseManager::$defaultRoles – 永夜 https://www.shuijingwanwq.com 没有不值得去解决的问题,也没有不值得去学习的技术! Mon, 18 May 2026 09:44:52 +0000 zh-Hans hourly 1 https://wordpress.org/?v=7.0 在 Yii2 中,需要判断当前登录用户是否具体接口访问权限(基于 RBAC、默认角色) https://www.shuijingwanwq.com/2025/05/26/9045/ https://www.shuijingwanwq.com/2025/05/26/9045/#comments Mon, 26 May 2025 02:14:40 +0000 https://www.shuijingwanwq.com/?p=9045 Post Views: 195

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

下一步不计划手动指定用户的角色,而是基于默认角色,自动指定。

图1


return [
    // ...
    'components' => [
        'authManager' => [
            'class' => 'yii\rbac\DbManager',
            // 'cache' => 'cache',
            'defaultRoles' => ['companyEmployee', 'conventionContact', 'checkinManager'],
        ],
        // ...
    ],
];


 

7、检查当前用户是否具有 accessConvention 权限。确认检查通过,具有 accessConvention 权限。通过 ‘can()’ 方法会检查角色和权限。用户拥有角色或其继承角色,符合预期。如图2

检查当前用户是否具有 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

检查当前用户是否具有 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'))


 

 

]]>
https://www.shuijingwanwq.com/2025/05/26/9045/feed/ 1