以前有個朋友問我yii的rbac怎麼作,之前大學的時候有接觸過,很長時間沒用了,也忘記了,正好這幾天比較閒,從新捋了下大致思路,但願能夠幫到困在yii的rbac上的門外han~~php
基於角色的權限訪問控制(Role-Based Access
Control)做爲傳統訪問控制(自主訪問,強制訪問)的有前景的代替受到普遍的關注。在RBAC中,權限與角色相關聯,用戶經過成爲適當角色的成員而獲得這些角色的權限。這就極大地簡化了權限的管理。在一個組織中,角色是爲了完成各類工做而創造,用戶則依據它的責任和資格來被指派相應的角色,用戶能夠很容易地從一個角色被指派到另外一個角色。角色可依新的需求和系統的合併而賦予新的權限,而權限也可根據須要而從某角色中回收。角色與角色的關係能夠創建起來以囊括更普遍的客觀狀況。html
用戶登陸後認證用戶的角色web
根據角色 查詢出該角色擁有的權限操做列表數據庫
訪問某一個權限(操做)時判斷該用戶是否擁有訪問的能力數組
yii如何實現呢??這裏咱們採用數據庫的方式實現,會相對來講比較安全安全
首先在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
而後,看看數據庫
過濾器的使用原理:
權限的控制實則就是判斷當前的用戶是否擁有對方法,控制器訪問的權限 在這以前須要使用過濾器 對用戶的登陸與未登陸進行認證過濾 ,全部的控制器 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 } ?>
這樣就實現了不一樣登陸用戶 不一樣菜單的展現
原理:
不一樣角色擁有不一樣權限,超級管理員能夠建立用戶,及分配權限給不一樣用戶,首先咱們得有個用戶->
/*角色添加*/ 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值
具體如何作呢?? 看這裏->
/* 分配權限 */ 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的規則,這又是個什麼東西呢?? 所謂的規則 其實就是對用戶的權限的額外限制
原理:
經過定義規則類,添加用戶的時候指定規則名稱 就能夠實現對用戶的權限的額外限制,
數據表中,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"); }
這樣再添加用戶的時候,就能夠指定規則,進而實現對更加高級的指定權限
到這裏,基本完成了用戶建立,權限分配,及規則指定,但願能夠幫到你們~~