Yii2 RBAC 权限管理

1. RBAC 权限管理基本概念;

相关概念:
Role Based Access Control:基于 角色的访问控制
RBAC 提供了一个简单而强大的集中式访问控制机制
关键字:
用户:Web 应用中的认证基数
角色 Role(角色是权限的集合):整合权限的集合,可以包含用户、也可以包含权限
权限 Permission(操作):控制器当中的相关方法
RBAC 权限认证流程:
用户登录后认证用户的角色
根据角色查询出角色该有的权限(操作)列表
当用户访问某一个权限(操作)是判断该用户是否拥有该操作的访问的能力
Yii2 的 RBAC 实现方式 1:数据库
储存角色或权限的表 auth_item
角色对应权限相关表 auth_item_child:角色拥有哪些权限
角色和权限同时存储在第一张表
用户角色(权限)表 auth_assignment:可以为用户分配角色,也可以为用户分配对应的权限
规则表 auth_role:提供额外权限的认证规则
// 注意:以下数据表不需要自己新建,运行命令后会自动化生成
// auth_item:存储角色或权限的表
// name:角色或者权限的名称
// type:角色或者权限的分类(1 角色,2 权限)
// description:描述
// rule_name:额外的规则名称
// data:规则数据
// created_at:创建时间
// updated_at:更新时间
INSERT INTO `auth_item` SET name = 'admin', type = 1, description = '管理员';
INSERT INTO `auth_item` SET name = 'category/*', type = 2, description = 'category/*';
INSERT INTO `auth_item` SET name = 'category/add', type = 2, description = 'category/add';
INSERT INTO `auth_item` SET name = 'category/del', type = 2, description = 'category/del';

// auth_item_child:角色对应权限表
// parent:角色
// child:权限
// 给超级管理员分配对应的权限
INSERT INTO `auth_item_child` SET parent = 'admin', child = 'category/*';
INSERT INTO `auth_item_child` SET parent = 'admin', child = 'category/add';

// auth_assignment 用户角色(权限)关联数据
// item_name:角色或者权限
// user_id:用户 id
// created_at:创建时间
// 对某个用户做角色或者权限的分配
INSERT INTO `auth_assignment` SET item_name = 'admin', user_id = 1;
INSERT INTO `auth_assignment` SET item_name = 'guest', user_id = 2;

// auth_role 存储规则数据
// name:规则名称
// data:规则数据
// created_at:创建时间
// updated_at:修改时间

数据表分析:
管理表:yii\rbac\DbManager
数据表不需要手动创建:yii migrate --migrationPath=@yii/rbac/migrations
Yii2 的 RBAC 实现方式 2:文件
@app/rbac 将权限数据全部都保存在应用目录下的 rbac 目录中
文件分析:
管理文件:yii\rbac\PhpManager
存储路径:@app/rbac
所有的数据文件不需要手动创建
使用基本类:
yii\rbac\Item:管理角色或者权限的基类,用字段 type 来区分
yii\rbac\Role:Role 为代表角色的类(Item 子类)
yii\rbac\Permission:控制权限操作的类(Item 子类)
yii\rbac\Assignment:给用户分配角色(权限),用户与角色的关联
yii\rbac\Rule:判断角色权限的额外规则

2. 配置 RBAC;

  • 关于 yii 命令
# 进入到项目目录
cd /data/project/test/yii22/basic
./yii hello/index
# 输出 hello world

# 从控制器 basic/commands/HelloController.php 的 index() 方法输出
# 为什么通过 ./yii 就能访问?
# 打开 yii 文件,是一个类似 basic/web/index 的入口文件
# 加载 basic/config/console.php 配置
# 既然 yii 可以运行一个控制器里的方法
# 那可以写一个控制器,写一个方法
# 将后台的所有的控制器和方法作为**权限节点**插入数据表中
  • 修改配置文件 basic/config/console.php
// 在 components 中添加以下代码
'authManager' => [
    'class' => 'yii\rbac\DbManager',
    'itemTable' => 'auth_item',
    'itemChildTable' => 'auth_item_child',
    'assignmentTable' => 'auth_assignment',
],
  • 生成 rbac 默认数据表
./yii migrate --migrationPath=@yii/rbac/migrations
# Apply the above migrations? (yes|no) [no]:
yes 

在这里插入图片描述

  • 新建 basic/commands/RbacController.php
<?php

namespace app\commands;

use Yii;
use yii\console\Controller;

class RbacController extends Controller{

    // 往数据表插入所有的权限节点
    // 执行:./yii rbac/init
    public function actionInit(){
        $trans = Yii::$app->db->beginTransaction();
        try{
            // 找到所有存放控制器的目录
            // 当前目录 dirname(__FILE__)
            // 跳出一级,追加 dirname()
            $dir = dirname(dirname(__FILE__)) . '/controllers';
            // 找目录下的所有文件
            $controllers = glob($dir . '/*');
            // var_dump($controllers);

            $permissions = [];
            foreach ($controllers as $controller){
                $content = file_get_contents($controller);
                // 找控制器名称
                // $match 为匹配到的内容
                preg_match('/class ([a-zA-Z]+)Controller/', $content, $match);
                // 控制器名称
                $cName = $match[1];
                $permissions[] = strtolower($cName . '/*');

                // 找方法名
                // preg_match_all() 匹配所有
                preg_match_all('/public function action([a-zA-Z_]+)/', $content, $matches);
                foreach ($matches[1] as $aName){
                    $permissions[] = strtolower($cName .'/'. $aName);
                }

            }
            // var_dump($permissions);

            // 数据表插入
            $auth = Yii::$app->authManager;
            foreach($permissions as $permission){
                if(!$auth->getPermission($permission)){
                    $obj = $auth->createPermission($permission);
                    $obj->description = $permission;
                    $auth->add($obj);
                }
            }
            $trans->commit();

            echo 'import success';

        } catch (\Exception $e){
            $trans->rollback();

            echo 'import fail';
            print_R($e->getMessage());

        }
    }
}
  • 批量导入节点
./yii rbac/init

3. 后台创建用户角色;

场景:
在后台权限列表里,点击“分配权限”,就应该给某一个角色去分配对应的权限的节点
在 Yii2 的 RBAC 中,提供了另外一种模式,不仅可以给角色添加 权限节点,还可以给角色添加 角色节点。假设普通用户拥有某些权限列表,当 manager 将 user 归纳为他下面的一个子角色的时候,manager 就拥有了 user 的所有权限。所以说在为一个角色分配权限的时候,可以分配两种内容:一种是可以给角色分配子角色,另外一种是可以给角色分配子节点
需要用到的表:shop_auth_item_child
  • 修改 basic/modules/controllers/RbacController.php
<?php

namespace app\modules\controllers

use Yii;
use yii\data\ActiveDataProvider;
use yii\db\Query;
use\app\modules\models\Rbac;

class RbacController extends CommonController{

	public $mustlogin = ['createrole', 'roles', 'assignitem'];

	public function actionAssignitem($name){
        $name = htmlspecialchars($name);
        // 获取所有的角色
        $auth = Yii::$app->authManager;
        // $roles = $auth->getRoles();
        // var_dump($roles);
        // 权限列表
        // $permissions = $auth->getPermissions();
        // var_dump($permissions);
        
        $parent = $auth->getRole($name);

		if (Yii::$app->request->isPost) {
            $post = Yii::$app->request->post();
            if (Rbac::addChild($post['children'], $name)) {
                Yii::$app->session->setFlash('info', '分配成功');
            }
        }
        
        $roles = Rbac::getOptions($auth->getRoles(), $parent);
        $permissions = Rbac::getOptions($auth->getPermissions(), $parent);
        
		return $this->render('_assignitem', [
			'parent' => $name, 
			'roles' => $roles, 
			'permissions' => $permissions, 
		]);
    
    }
}

  • 修改 basic/modules/models/Rbac.php
<?php

namespace app\modules\models;

use yii\db\ActiveRecord;
use Yii;

class Rbac extends ActiveRecord {

	// $parent 给当前角色分配的角色
	public static function getOptions($data, $parent){
		$return = [];
		
		foreach ($data as $obj) {
			// 不为空,
			// 分配的角色和当前角色不同,
			// 当前的权限节点、角色节点能不能被分配($parent 是否能添加 $obj 节点)
			if(!empty($parent) && 
				$parent->name != $obj->name && 
				Yii::$app->authManager->canAddChild($parent, $obj)){
				$return[$obj->name] = $obj->description;
			}
		}
		return $return;
	}

	public static function addChild($children, $name){
        $auth = Yii::$app->authManager;
        // 获取 $name 对象
        $itemObj = $auth->getRole($name);
        if (empty($itemObj)) {
            return false;
        }
        $trans = Yii::$app->db->beginTransaction();
        try {
        	// 添加前先删除数据
            $auth->removeChildren($itemObj);
            foreach ($children as $item) {
            	// 有可能是角色 有可能是权限
                $obj = empty($auth->getRole($item)) ? $auth->getPermission($item) : $auth->getRole($item);
                $auth->addChild($itemObj, $obj);
            }
            $trans->commit();
        } catch(\Exception $e) {
            $trans->rollback();
            return false;
        }
        return true;
    }
}

发布了119 篇原创文章 · 获赞 12 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/hualaoshuan/article/details/102153289