yii2 advanced rbac 权限管理

1.项目配置

这里说明的rbac使用的是DB ,所以打开config中main.php文件,在components里加入下面代码

'components' => [
        'authManager' => [
            'class' => 'yii\rbac\DbManager',//使用DB 数据更安全
            // auth_item (role permission)
            // auth_item_child (role->permission)
            // auth_assignment (user->role)
            // auth_rule (rule)
            'itemTable' => '{{%auth_item}}',
            'itemChildTable' => '{{%auth_item_child}}',
            'assignmentTable' => '{{%auth_assignment}}',
            'ruleTable' => '{{%auth_rule}}',
            'defaultRoles' => ['default'],
        ],
]


2.通过yii命令 创建rbac数据表 并创建表对应 model

yii2提供 rbac数据表的创建(文件位置:vendor/yiisoft/yii2/rbac/migrations/schema-sqlite.sql),打开app/console/config/main.php 添加

'components' => [
         'authManager' => [
            'class' => 'yii\rbac\DbManager',//使用DB 数据更安全
            // auth_item (role permission)
            // auth_item_child (role->permission)
            // auth_assignment (user->role)
            // auth_rule (rule)
            'itemTable' => '{{%auth_item}}',
            'itemChildTable' => '{{%auth_item_child}}',
            'assignmentTable' => '{{%auth_assignment}}',
            'ruleTable' => '{{%auth_rule}}',
        ],
        
    ],

在项目根目录下 打开cmd 输入:

$ ./yii migrate --migrationPath=@yii/rbac/migrations

执行中提示是否执行,输入yes即可,执行成功后查看数据库增加四张表即表示成功

之后浏览器 输入 projecturl(项目url)/index.php?r=gii,选择model 创建四张权限表对应的model

3.创建用户角色

 a.创建rabc控制器 RbacController.php 并打开

<?php

namespace backend\controllers;

use Yii;
use yii\web\Controller;


class RbacController extends CommonController
{
   public function actionCreaterole()
    {
        //提交操作
        if (Yii::$app->request->isPost) {
            $auth = Yii::$app->authManager;//拿取权限角色
            $role = $auth->createRole(null);//role 名称先赋值为空

            $post = Yii::$app->request->post();
            //name 和 description 不能为空
            if (empty($post['name']) || empty($post['description'])) {
                throw new \Exception('参数错误');
            }
            $role->name = $post['name'];
            $role->description = $post['description'];
            $role->ruleName = empty($post['rule_name']) ? null : $post['rule_name'];
            $role->data = empty($post['data']) ? null : $post['data'];
            //添加成功
            if ($auth->add($role)) { //操作表为 auth_item
                Yii::$app->session->setFlash('success', '添加成功');
            }
        }
        return $this->render('_createitem');
    }
}

  b.创建view 在app\backend\views\rbac\_createitem.php 并打开

<?php

use yii\helpers\Html;
use yii\grid\GridView;
use common\models\Product;
use yii\bootstrap\ActiveForm;

/* @var $this yii\web\View */
/* @var $searchModel common\models\ProductSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = '添加角色';

$this->params['breadcrumbs'][] = ['label' => '角色管理', 'url' => ['rbac/roles']];
$this->params['breadcrumbs'][] = $this->title;

?>
<div class="createitem-index">
    <div class="container">
        <?php
        if (Yii::$app->session->hasFlash('info')) {
            echo Yii::$app->session->getFlash('info');
        }
        $form = ActiveForm::begin([
            'options' => [
                'class' => 'form-horizontal',
                'enctype' => 'multipart/form-data'
            ],//form 表单样式

            'fieldConfig' => [
                'options' => [
                    'tag'=>'span'
                ],
                'template' => '{label}{input}{error}'
            ],
        ]);

        ?>
        <div class="row">
            <div class="col-md-6">
                <?php echo Html::label('名称', null). Html::textInput('description', '', ['class' => 'form-control']); ?>
            </div>
            <div class="col-md-6">
                <?php echo Html::label('标识', null). Html::textInput('name', '', ['class' => 'form-control']); ?>
            </div>
        </div>
        <div class="row">
            <div class="col-md-6">
                <?php echo Html::label('规则名称', null). Html::textInput('rule_name', '', ['class' => 'form-control']); ?>
            </div>

        </div>

        <div class="row">

            <div class="col-md-12">
                <?php echo Html::label('数据', null). Html::textarea('data', '', ['class' => 'form-control']); ?>
            </div>
        </div>


        <div class="row">
            <div class="col-md-12">
                <?= Html::submitButton('创建' , ['class' => 'btn btn-success']) ?>
            </div>
        </div>
        <?php ActiveForm::end(); ?>
    </div>

</div>

c.创建角色 查看{{%auth_item}}表是否有添加数据

4.显示角色列表

a.打开 backend/controllers/RbacController.php 添加方法 actionIndex()

use backend\models\BsellerAuthItem;
use yii\data\Pagination;
.....
class RbacController extends Controller{
    ......
    //角色列表
    public function actionIndex()
    {
      
        $query = BsellerAuthItem::find()->where('type = 1')->orderBy('created_at desc');

       $count = $query->count(); //数据总个数
        $pageSize = Yii::$app->params['pageSize']['defaultPageSize']; //获取 config/params.php 中设置的页数
        $pager = new Pagination(['totalCount' => $count, 'pageSize' => $pageSize]); //分页

        $models = $query->offset($pager->offset)->limit($pager->limit)->all(); //获取分页后的数据

        return $this->render('index', [
            'pager' => $pager,
            'models' => $models,
        ]);

    }

}

 创建并打开backend/views/rbac/index.php

<?php

use yii\helpers\Html;
use yii\grid\GridView;
use common\models\PurchaseOffer;

/* @var $this yii\web\View */
/* @var $searchModel common\models\PurchaseSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = '角色列表';
$this->params['breadcrumbs'][] = $this->title;

?>
<div class="purchase-index">

    <p>
        <?= Html::a('添加角色', ['createrole'], ['class' => 'btn btn-success']) ?>
    </p>

    <div class="row">
        <div class="col-md-12">
            <table class="table table-hover table-bordered">
                <thead>
                <tr>
                <tr>
                    <th class="">
                       名称
                    </th>
                    <th>
                        标识
                    </th>
                    <th class="">
                        规则名称
                    </th>

                    <th class="">
                        创建时间
                    </th>

                    <th class="align-right">
                        操作
                    </th>

                </tr>
                </tr>
                </thead>
                <tbody>
                <!-- row -->
                <?php foreach($models as $model): ?>

                    <tr class="">
                        <td>
                           <?= $model['description'] ?>
                        </td>
                        <td>
                            <?= $model['name'] ?>
                        </td>
                        <td>
                            <?= $model['rule_name'] ?>
                        </td>
                        <td>
                            <?= date("Y-m-d h:i", $model['created_at']) ?>

                        </td>

                        <td class="align-right">
                            <?=Html::a('分配权限', ['view', 'name' => $model['name']])?> |
                            <?=Html::a('更新', ['view', 'name' => $model['name']])?> |
                            <?=Html::a('删除', ['view', 'name' => $model['name']])?>

                        </td>
                    </tr>
                <?php endforeach; ?>
                </tbody>
            </table>
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            <div class="pagination pull-right">
                <!-- 分页组件  prevPageLabel上一页  nextPageLabel下一页-->
                <?php echo yii\widgets\LinkPager::widget(['pagination' => $pager, 'prevPageLabel' => '&#8249;', 'nextPageLabel' => '&#8250;']); ?>
            </div>
        </div>
    </div>




5.console 命令行一键获取所有权限

创建并打开console/controllers/RabcController.php

<?php
namespace console\controllers;

use Yii;
use yii\console\Controller;

/**
 * CommentController implements the CRUD actions for CommentProduct model.
 */
class RbacController extends Controller
{
    public function actionInit()
    {
        $trans = Yii::$app->db->beginTransaction();
        try {
            $dir = dirname(dirname(dirname(__FILE__))). '/backend/controllers';
            $controllers = glob($dir. '/*');
            $permissions = [];
            foreach ($controllers as $controller) {
                $content = file_get_contents($controller);
                preg_match('/class ([a-zA-Z]+)Controller/', $content, $match);
                $cName = $match[1];
                $permissions[] = strtolower($cName. '/*');
                preg_match_all('/public function action([a-zA-Z_]+)/', $content, $matches);
                foreach ($matches[1] as $aName) {
                    $permissions[] = strtolower($cName. '/'. $aName);
                }
            }
            $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 \n";
        } catch(\Exception $e) {
            $trans->rollback();
            echo "import failed \n";
        }
    }
}

在项目根目录下 打开cmd 输入:

$ ./yii rbac/init
import success 

执行成功后 进入数据库查看item看是否导入成功(接口列表 在item表里面 type = 2)

6.角色分配权限子节点和角色子节点

a.打开 backend/controllers/RbacController.php 添加方法 actionAssignitem($name)

//角色分配权限
    public function actionAssignitem($name)
    {
        //防止注入
        $name = htmlspecialchars($name);
        $auth = Yii::$app->authManager;
        //获取当前角色
        $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', '分配成功');
                return $this->redirect(['rbac/index']);
            }
        }
        //获取对应角色 下的权限
        $children = Rbac::getChildrenByName($name);


        //获取所有角色 并拼成数组
        $roles = Rbac::getOptions($auth->getRoles(), $parent);
        //获取所有权限 并拼成数组
        $permissions = Rbac::getOptions($auth->getPermissions(), $parent);

        return $this->render('_assignitem', ['parent' => $name, 'roles' => $roles, 'permissions' => $permissions, 'children' => $children]);
    }

b.创建并打开 backend\models\Rbac.php

<?php
namespace backend\models;

use yii\db\ActiveRecord;
use Yii;

class Rbac extends ActiveRecord
{
    //获取 接口节点 数组
    public static function getOptions($data, $parent)
    {
        $return = [];
        foreach ($data as $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;
        //拿到角色
        $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;
    }


    //获取对应角色 下的权限
    public static function getChildrenByName($name)
    {

        if (empty($name)) {

            return [];
        }
        $return = [];
        $return['roles'] = [];
        $return['permissions'] = [];

        $auth = Yii::$app->authManager;
        $children = $auth->getChildren($name);
        if (empty($children)) {
            return $return;
        }
        foreach ($children as $obj) {
            //如果是1 为角色
            if ($obj->type == 1) {
                $return['roles'][] = $obj->name;
            } else { //如果是2 则为权限
                $return['permissions'][] = $obj->name;
            }
        }

        return $return;
    }
}

c.创建权限分配页面,创建并打开backend\views\rbac\_assignitem.php

<?php

use yii\helpers\Html;
use yii\grid\GridView;
use common\models\Product;
use yii\bootstrap\ActiveForm;

/* @var $this yii\web\View */
/* @var $searchModel common\models\ProductSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = '分配权限';

$this->params['breadcrumbs'][] = ['label' => '角色列表', 'url' => ['rbac/index']];
$this->params['breadcrumbs'][] = $this->title;

?>
<div class="createitem-index">
    <div class="container">
        <?php
        if (Yii::$app->session->hasFlash('info')) {
            echo Yii::$app->session->getFlash('info');
        }
        $form = ActiveForm::begin([
            'options' => [
                'class' => 'form-horizontal',
                'enctype' => 'multipart/form-data'
            ],//form 表单样式

            'fieldConfig' => [
                'options' => [
                    'tag'=>'span'
                ],
                'template' => '{label}{input}{error}'
            ],
        ]);

        ?>
        <div class="row">
            <div class="col-md-12">
              <h2> <?php echo Html::label('角色名称', null). Html::encode($parent); ?> </h2>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <?php echo Html::label('角色子节点', null). Html::checkboxList('children', $children['roles'], $roles);  ?>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <?php echo Html::label('权限子节点', null). Html::checkboxList('children', $children['permissions'], $permissions); ?>
            </div>
        </div>

        <div class="row">
            <div class="col-md-12">
                <?= Html::submitButton('创建' , ['class' => 'btn btn-success']) ?>
            </div>
        </div>
        <?php ActiveForm::end(); ?>
    </div>

</div>

d.跑通测试: 进入权限列表页,选择一条数据 点击进入分配权限,进入后可以分配角色(系统将把角色下的权限分配给此操作对象),也可以选择复选框进行制定分配权限,创建完,打开数据表 {{%auth_item_child}},查看是否成功分配权限.

7.后台管理员授权

a.打开管理员controller层,本项目地址为 backend\controllers\AdminController.php,添加方法 actionAssign

<?php
.......
use backend\models\Rbac;
.......

.......
//管理员授权
    public function actionAssign($adminid)
    {
        $this->layout = "main";

        $adminid = (int)$adminid;
        if (empty($adminid)) {
            throw new \Exception('参数错误');
        }

        $admin = Admin::findOne($adminid);
        if (empty($admin)) {
            throw new \yii\web\NotFoundHttpException('admin not found');
        }

        if (Yii::$app->request->isPost) {
            $post = Yii::$app->request->post();
            $children = !empty($post['children']) ? $post['children'] : [];
            if (Rbac::grant($adminid, $children)) {
                Yii::$app->session->setFlash('info', '授权成功');
            }
        }

        $auth = Yii::$app->authManager;
        //获取所有角色
        $roles = Rbac::getOptions($auth->getRoles(), null);
        //获取所有授权
        $permissions = Rbac::getOptions($auth->getPermissions(), null);

        //获取用户 的授权/角色
        $children = Rbac::getChildrenByUser($adminid);
        return $this->render('_assign', ['children' => $children, 'roles' => $roles, 'permissions' => $permissions, 'admin' => $admin->adminuser]);
    }

b.修改backend/models/Rbac.php 中getOptions($data,$parent)方法,并且添加多个管理员授权方法

  //修改处
 //获取 接口节点 数组
    public static function getOptions($data, $parent)
    {
        $return = [];
        foreach ($data as $obj) {
            //为能为空&&不能为角色自身&&是否能够分配
            if (!empty($parent) && $parent->name != $obj->name && Yii::$app->authManager->canAddChild($parent, $obj)) {
                $return[$obj->name] = $obj->description;
            }
            //为管理员授权
            if(is_null($parent)){
                $return[$obj->name] = $obj->description;
            }
        }
        return $return;
    }



//添加处 

//获取管理员已有的 角色/授权
    private static function _getItemByUser($adminid, $type)
    {
        // $func 为 函数名称为
        $func = 'getPermissionsByUser';
        if ($type == 1) {
            $func = 'getRolesByUser';
        }
        $data = [];
        $auth = Yii::$app->authManager;
        $items = $auth->$func($adminid);
        foreach ($items as $item) {
            $data[] = $item->name;
        }
        return $data;
    }

    //获取管理员 权限
    public static function getChildrenByUser($adminid)
    {
        $return = [];
        //获取管理员分配到的角色
        $return['roles'] = self::_getItemByUser($adminid, 1);
        //获取管理员分配到的权限
        $return['permissions'] = self::_getItemByUser($adminid, 2);
        return $return;
    }

    //操作{{%auth_assignment}}
    public static function grant($adminid, $children)
    {
        $trans = Yii::$app->db->beginTransaction();
        try {
            $auth = Yii::$app->authManager;
            //先清除授权
            $auth->revokeAll($adminid);
            foreach ($children as $item) {
                //如果角色为空(不为角色)?返回角色 : 返回权限
                $obj = empty($auth->getRole($item)) ? $auth->getPermission($item) : $auth->getRole($item);
                $auth->assign($obj, $adminid);
            }
            $trans->commit();
        } catch (\Exception $e) {
            $trans->rollback();
            return false;
        }
        return true;
    }

c.新建管理员授权试图,创建并修改 backend\views\admin\_assign.php

<?php

use yii\helpers\Html;
use yii\grid\GridView;
use common\models\Product;
use yii\bootstrap\ActiveForm;

/* @var $this yii\web\View */
/* @var $searchModel common\models\ProductSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = '授权';

$this->params['breadcrumbs'][] = ['label' => '管理员列表', 'url' => ['admin/index']];
$this->params['breadcrumbs'][] = $this->title;

?>
<div class="createitem-index">
    <div class="container">
        <?php
        if (Yii::$app->session->hasFlash('info')) {
            echo Yii::$app->session->getFlash('info');
        }
        $form = ActiveForm::begin([
            'options' => [
                'class' => 'form-horizontal',
                'enctype' => 'multipart/form-data'
            ],//form 表单样式

            'fieldConfig' => [
                'options' => [
                    'tag'=>'span'
                ],
                'template' => '{label}{input}{error}'
            ],
        ]);

        ?>
        <div class="row">
            <div class="col-md-12">
               <h2>
                   <?php echo Html::label('管理员', null). Html::encode($admin); ?>
               </h2>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <?php echo Html::label('角色', null). Html::checkboxList('children', $children['roles'], $roles); ?>
            </div>
        </div>
        <div class="row">
            <div class="col-md-12">
                <?php echo Html::label('权限', null). Html::checkboxList('children', $children['permissions'], $permissions); ?>
            </div>
        </div>

        <div class="row">
            <div class="col-md-12">
                <?= Html::submitButton('创建' , ['class' => 'btn btn-success']) ?>
            </div>
        </div>
        <?php ActiveForm::end(); ?>
    </div>

</div>

b.验证步骤 创建完查看 {{%auth_assignment}} 表中item_name 为 权限名 or 角色名 ,user_id 为管理员id

8.后台管理员权限认证

a.backend/controllers里定义一个父类控制层 CommonController.php ,其他控制层都继承如:

......
class RbacController extends CommonController{
   ......
}

b.修改 backend/controllers/CommonController.php

<?php
namespace backend\controllers;

use Yii;
use yii\web\Controller;



/**
 * Site controller
 */
class CommonController extends Controller
{
    
    //管理员权限认证
    public function beforeAction($action)
    {

        if (!parent::beforeAction($action)) {
            return false;
        }


        //为控制器请求
        $controller = $action->controller->id;
        //为方法请求
        $actionName = $action->id;
       


        if (Yii::$app->admin->can($controller. '/*')) {
            return true;
        }
        if (Yii::$app->admin->can($controller. '/'. $actionName)) {
            return true;
        }
        throw new \yii\web\UnauthorizedHttpException('对不起,您没有访问'. $controller. '/'. $actionName. '的权限');
        //return true;
    }



    public function init()
    {
//        if (Yii::$app->session['admin']['isLogin'] != 1) {
//            return $this->redirect(['/admin/public/login']);
//        }
    }
}

其中$controller为请求指向的控制器名称,$actionName为方法名,Yii::$app->admin 为用户登录认证后调用的方法(这里对yii2 用户登录不清楚的盆友请先了解 yii2用户登录认证体系).

9.根据权限显示菜单

a.创建和修改backend\config\adminmenu.php

<?php
return [
    'adminmenu' =>[
        ['label' => '首页', 'url' => 'site/index', 'module' => 'site', 'icon' => 'fa-home'],
        ['label' => '管理员管理', 'url' => '#', 'module' => 'admin', 'icon' => 'fa-home', 'submenu' => [
            ['label' => '管理员列表', 'url' => 'index']
        ]],
        ['label' => '权限管理', 'url' => '#', 'module' => 'rbac', 'icon' => 'fa-home', 'submenu' => [
            ['label' => '权限列表', 'url' => 'index']
        ]],    
    ]
];

b.添加adminmenu.php 添加到项目参数里,修改backend\config\main.php 

<?php
$params = array_merge(
    require(__DIR__ . '/../../common/config/params.php'),
    require(__DIR__ . '/../../common/config/params-local.php'),
    require(__DIR__ . '/params.php'),
    require(__DIR__ . '/params-local.php'),
    require(__DIR__ . '/adminmenu.php')
);
........

c.根据权限遍历菜单,因为每个后台项目管理用的菜单样式不同,所以这里需要理解,勿照搬照抄,根据项目进行改动

  <ul class="nav nav-pills nav-stacked nav-quirk">
                        <?php

                        $controller = Yii::$app->controller->id;//请求控制器
                        $action = Yii::$app->controller->action->id;//请求方法
                        foreach (Yii::$app->params['adminmenu'] as $menu) {//遍历菜单

                            $show = "hidden";//隐藏样式
                            //判断管理员是否有该控制器的权限 
                            if (Yii::$app->admin->can($menu['module']. '/*')) {
                                $show = "show";//全部显示
                            } else {
                                
                                if (empty($menu['submenu']) && !Yii::$app->admin->can($menu['url'])) {
                                    continue;
                                } else {
                                    foreach ($menu['submenu'] as $sub) {
                                        if (Yii::$app->admin->can($menu['module']. '/'. $sub['url'])) {
                                            $show = "show";
                                        }
                                    }
                                }
                            }
                            ?>
                            <li class="<?php echo !empty($menu['submenu']) ? 'nav-parent ' : ''; echo $controller == $menu['module'] ? 'active ' : ''; echo $show; ?>">
                                <a  href="<?php echo $menu['url'] == '#' ? '#' : yii\helpers\Url::to([$menu['url']]); ?>">
                                    <i class="fa <?php echo $menu['icon'] ?>"></i>
                                    <span><?php echo $menu['label']; ?></span>
                                </a>
                                <?php if (!empty($menu['submenu'])) : ?>
                                        <ul class="children <?php echo $controller == $menu['module'] && !empty($menu['submenu']) ? 'active' : ''; ?>">

                                            <?php foreach ($menu['submenu'] as $sub): ?>
                                                <?php if (!Yii::$app->admin->can($menu['module']. '/*') && !Yii::$app->admin->can($menu['module']. '/'. $sub['url'])) continue; ?>

                                                    <li class="<?php echo $action == $sub['url'] ? 'active ' : ''; echo $show; ?>">


                                                        <a href="<?php echo yii\helpers\Url::to([$menu['module']. '/'. $sub['url']]); ?>"><?php echo $sub['label'] ?></a>
                                                   </li>
                                            <?php endforeach; ?>

                                        </ul>

                                    <?php endif; ?>
                            </li>
                            <?php
                        }
                        ?>
                        </ul>

结束

转载于:https://my.oschina.net/oslph/blog/1545924

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值