yii實現rbac詳解

以前有個朋友問我yii的rbac怎麼作,之前大學的時候有接觸過,很長時間沒用了,也忘記了,正好這幾天比較閒,從新捋了下大致思路,但願能夠幫到困在yii的rbac上的門外han~~php

RBAC~~什麼是RBAC

基於角色的權限訪問控制(Role-Based Access
Control)做爲傳統訪問控制(自主訪問,強制訪問)的有前景的代替受到普遍的關注。在RBAC中,權限與角色相關聯,用戶經過成爲適當角色的成員而獲得這些角色的權限。這就極大地簡化了權限的管理。在一個組織中,角色是爲了完成各類工做而創造,用戶則依據它的責任和資格來被指派相應的角色,用戶能夠很容易地從一個角色被指派到另外一個角色。角色可依新的需求和系統的合併而賦予新的權限,而權限也可根據須要而從某角色中回收。角色與角色的關係能夠創建起來以囊括更普遍的客觀狀況。html

RBAC~~權限認證流程

  1. 用戶登陸後認證用戶的角色web

  2. 根據角色 查詢出該角色擁有的權限操做列表數據庫

  3. 訪問某一個權限(操做)時判斷該用戶是否擁有訪問的能力數組

yii如何實現呢??這裏咱們採用數據庫的方式實現,會相對來講比較安全安全

RBAC~~權限數據生成

首先在web/console.php中配置組件session

'authManager' => [
    'class' => 'yii\rbac\DbManager',
    // 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}}',
],

接着使用yii腳本,生成數據表app

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

而後咱們須要讀取全部的控制器與方法 存儲到權限表,方便判斷的時候 讀取數據庫 進而進行判斷yii

public function actionInit()
{
    $trans = Yii::$app->db->beginTransaction();
    try {
        //構建控制器目錄
        $dir = dirname(dirname(__FILE__)). '/modules/controllers';
        //找到控制器目錄下的全部文件
        $controllers = glob($dir. '/*');
        $permissions = [];
        foreach ($controllers as $controller) {
            $content = file_get_contents($controller);
            //找到Controller便可
            preg_match('/class ([a-zA-Z]+)Controller/', $content, $match);
            $cName = $match[1];
            $permissions[] = strtolower($cName. '/*');
            //正則匹配文本中的因此action
            preg_match_all('/public function action([a-zA-Z_]+)/', $content, $matches);
            foreach ($matches[1] as $aName) {
                $permissions[] = strtolower($cName. '/'. $aName);
            }
        }
        $auth = Yii::$app->authManager;

        //爲何$auth能夠操做到該表
        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";
    }
}

接着yii下 就能夠生成權限數據了post

./yii rbac/init

而後,看看數據庫

clipboard.png

RBAC~~權限訪問控制

過濾器的使用原理:

權限的控制實則就是判斷當前的用戶是否擁有對方法,控制器訪問的權限 在這以前須要使用過濾器 對用戶的登陸與未登陸進行認證過濾 ,全部的控制器 extends CommonController,在訪問子類控制器的時候,會自動去訪問behaviors方法,在子控制器中,經過重寫父類的屬性指定容許訪問的方法,進而實現過濾的做用。

//子類能夠經過重寫該屬性 實現認證
 public $mustlogin = ['createrule', 'createrole', 'roles', 'assignitem'];
 //行爲過濾器
 public function behaviors()
    {
        return [
            'access' => [
                'class' => \yii\filters\AccessControl::className(),
                'user' => 'admin',
                'only' => $this->actions,
                'except' => $this->except,
                'rules' => [
                    [
                        'allow' => false,
                        'actions' => empty($this->mustlogin) ? [] : $this->mustlogin,
                        'roles' => ['?'],
                    ],
                    [
                        'allow' => true,
                        'actions' => empty($this->mustlogin) ? [] : $this->mustlogin,
                        'roles' => ['@'],
                    ],
                ],
            ],
        ];
    }

//那麼如何實現訪問 判斷用戶是否擁有權限呢??yii提供了beforeAction,在CommonController進行判斷

     /*權限訪問判斷*/
    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;
    }

//這樣便可實現權限的訪問控制

到這裏,咱們就是實現了權限的訪問判斷,接下來 咱們還要實現 不一樣用戶顯示不一樣的菜單,如何實現呢??

原理:
將菜單欄以數組的形式進行存儲,經過循環數組,判斷當前用戶訪問的控制器是否擁有對應的權限

<?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 $controller == $menu['module'] ? 'active' : ''; echo $show; ?>">
                <a <?php echo !empty($menu['submenu']) ? 'class="dropdown-toggle"' : ''; ?> href="<?php echo $menu['url'] == '#' ? '#' : yii\helpers\Url::to([$menu['url']]); ?>">
                    <i class="<?php echo $menu['icon'] ?>"></i>
                    <span><?php echo $menu['label']; ?></span>
                    <?php if (!empty($menu['submenu'])) : ?>
                    <i class="icon-chevron-down"></i>
                    <?php endif; ?>
                </a>
                    <ul class="submenu <?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><a href="<?php echo yii\helpers\Url::to([$menu['module']. '/'. $sub['url']]); ?>"><?php echo $sub['label'] ?></a></li>
                    <?php endforeach; ?>
                </ul>
            </li>
            <?php
                }
            ?>

這樣就實現了不一樣登陸用戶 不一樣菜單的展現

RBAC~~建立不一樣角色

原理:
不一樣角色擁有不一樣權限,超級管理員能夠建立用戶,及分配權限給不一樣用戶,首先咱們得有個用戶->

/*角色添加*/
    public function actionCreaterole()
    {
        if (Yii::$app->request->isPost) {
            //DBmanager對象
            $auth = Yii::$app->authManager;
            //建立一個role的對象
            $role = $auth->createRole(null);
            $post = Yii::$app->request->post();
            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)) {
                Yii::$app->session->setFlash('info', '添加成功');
            }
        }
        return $this->render('_createitem');
    }

原理:
所謂的分配權限就是將給用戶分配是否能夠訪問控制器的權限,確認要分配的對象 實則是指定表的user_id對應的item_name值

clipboard.png

具體如何作呢?? 看這裏->

/* 分配權限 */
    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', '分配成功');
            }
        }
        $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]);
    }

RBAC~~規則指定,更高級的權限指定

接下來,不得不談談rbac的規則,這又是個什麼東西呢?? 所謂的規則 其實就是對用戶的權限的額外限制
原理:
經過定義規則類,添加用戶的時候指定規則名稱 就能夠實現對用戶的權限的額外限制,
數據表中,data字段就是實例化的自定義規則類對象

好比咱們定義這樣一個自定義規則類

/*實現分類只能由添加者刪除*/
class AuthorRule extends Rule
{
    public $name = "isAuthor";
    //當前的用戶,權限,額外的參數
    public function execute($user, $item, $params)
    {
        $action = Yii::$app->controller->action->id;
        //對delete方法 進行額外限制
        if ($action == 'delete') {
            //獲取到當前分類是由那個用戶添加的  不容許其餘用戶刪除
            $cateid = Yii::$app->request->get("id");
            $cate = Category::findOne($cateid);
            return $cate->adminid == $user;
        }
        return true;
    }
}

咱們如何建立這個規則到數據表中呢??

/*建立規則*/
    public function actionCreaterule()
    {
        if (Yii::$app->request->isPost) {
            $post = Yii::$app->request->post();
            if (empty($post['class_name'])) {
                throw new \Exception('參數錯誤');
            }
            //指定當前的規則命名空間
            $className = "app\\models\\". $post['class_name'];
            if (!class_exists($className)) {
                throw new \Exception('規則類不存在');
            }
            $rule = new $className;
            //使用authManager組件將當前的規則類 保存到數據庫
            if (Yii::$app->authManager->add($rule)) {
                Yii::$app->session->setFlash('info', '添加成功');
            }
        }
        return $this->render("_createrule");
    }

這樣再添加用戶的時候,就能夠指定規則,進而實現對更加高級的指定權限

到這裏,基本完成了用戶建立,權限分配,及規則指定,但願能夠幫到你們~~

相關文章
相關標籤/搜索