1、RBAC的前期準備php
RBAC的權限管理須要知道怎麼給用戶分配角色,給角色分配權限,以權限來精細化須要的操做,判斷是否有權限來操做這一步,達到管理權限的目的。 先展現下要達到的效果 :
左邊爲三劍客:用戶、角色、權限;
下面爲測試頁面
2、RBAC的數據表
用戶表用的是yii2-admin中migration裏面的用戶表web
create table `user` ( `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `username` varchar(32) NOT NULL, `auth_key` varchar(32) NOT NULL, `password_hash` varchar(256) NOT NULL, `password_reset_token` varchar(256), `email` varchar(256) NOT NULL, `status` integer not null default 1, `created_at` integer not null, `updated_at` integer not null, KEY `email` (`email`) )ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `role` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL DEFAULT '' COMMENT '角色名稱', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '狀態 1:有效 0:無效', `updated_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '最後一次更新時間', `created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表'; CREATE TABLE `permission` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `title` varchar(50) NOT NULL DEFAULT '' COMMENT '權限名稱', `urls` varchar(1000) NOT NULL DEFAULT '' COMMENT 'json 數組', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '狀態 1:有效 0:無效', `updated_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '最後一次更新時間', `created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入時間', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='權限詳情表'; CREATE TABLE `user_role` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `uid` int(11) NOT NULL DEFAULT '0' COMMENT '用戶id', `role_id` int(11) NOT NULL DEFAULT '0' COMMENT '角色ID', `created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入時間', PRIMARY KEY (`id`), KEY `uid` (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶角色表'; CREATE TABLE `role_permisson` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `role_id` int(11) NOT NULL DEFAULT '0' COMMENT '角色id', `permission_id` int(11) NOT NULL DEFAULT '0' COMMENT '權限id', `created_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '插入時間', PRIMARY KEY (`id`), KEY `role_id` (`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色權限表';
3、視圖渲染部分。
將準備好的頁面放到views層,在models層創建和表相對應的文件
文件結構:
models層:
數據庫
view層:
json
4、邏輯部分:
以角色的增長和修改、給角色增長權限爲例:
一、RoleController代碼:數組
<?php namespace app\controllers; use Yii; use app\models\Permission; use app\models\Role; use app\models\RolePermission; class RoleController extends BaseController { public $layout = 'rbac'; /* *方法講解: *獲取有效的角色在視圖角色列表渲染 */ public function actionIndex(){ $roles = Role::find()->where([ 'status' => 1 ])->orderBy(['id'=>SORT_DESC])->all(); return $this->render('index',['roles'=>$roles]); } /* *方法講解: *編輯+新增 *一、若是能獲取到角色的id。則從數據庫取出數據來渲染。若沒有則渲染不顯示數據 *二、提交更新相應的修改或者增長。一樣以id來區分 *三、新增方法簡化還可用load()方法 */ public function actionEdit(){ if (Yii::$app->request->isPost){ //這個request方法是封裝的獲取參數的方法在後面的BaseController裏面能夠找到 $id = $this->request("id",0); $name = $this->request("name",""); $date_now = date("Y-m-d H:i:s"); //驗證參數TODO: $role = Role::find()->where([ 'id' => $id ])->one(); if( $role ){//編輯動做 $role = $role; }else{//添加動做 $role = new Role(); $role->status = 1; $role->created_time = $date_now; } $role->name = $name; $role->updated_time = $date_now; $res = $role->save(0); if ($res){ return $this->redirect('/role/index'); } } $id = $this->request("id",0); $role = []; if( $id ){ $role = Role::find()->where([ 'id' => $id ])->one(); } return $this->render("edit",[ "role" => $role ]); } /* *最重要的一步:展現權限和該角色已經擁有的權限 */ public function actionSet(){ if (Yii::$app->request->isPost){ //實現保存選中權限的邏輯 $id = $this->request("id",0); $permission_ids = $this->request("permission_ids",[]); //驗證參數TODO: //取出全部已分配給指定角色的權限 $role_permission_list = RolePermission::find()->where([ 'role_id' => $id ])->asArray()->all(); $assign_permission_ids = array_column( $role_permission_list,'permission_id' ); /** * 找出刪除的權限 * 假如已有的權限集合是A,界面傳遞過得權限集合是B * 權限集合A當中的某個權限不在權限集合B當中,就應該刪除 * 使用 array_diff() 計算補集 */ $delete_permission_ids = array_diff( $assign_permission_ids,$permission_ids ); if( $delete_permission_ids ){ RolePermission::deleteAll([ 'role_id' => $id,'permission_id' => $delete_permission_ids ]); } /** * 找出添加的權限 * 假如已有的權限集合是A,界面傳遞過得權限集合是B * 權限集合B當中的某個權限不在權限集合A當中,就應該添加 * 使用 array_diff() 計算補集 */ $new_permission_ids = array_diff( $permission_ids,$assign_permission_ids ); if( $new_permission_ids ){ foreach( $new_permission_ids as $permission_id ){ $role_permission = new RolePermission(); $role_permission->role_id = $id; $role_permission->permission_id = $permission_id; $role_permission->created_time = date("Y-m-d H:i:s"); $role_permission->save( 0 ); } } return $this->redirect('/role/index'); } $id = $this->request("id",0); //驗證數據TODO: $role = Role::find()->where([ 'id' => $id ])->one(); //取出全部的權限 $permissions = Permission::find()->where([ 'status' => 1 ])->orderBy( [ 'id' => SORT_DESC ])->all(); //取出全部已分配的權限 $role_permission= RolePermission::find()->where([ 'role_id' => $id ])->asArray()->all(); $role_permission_ids = array_column( $role_permission,"permission_id" ); return $this->render("set",[ "role" => $role, 'permissions' => $permissions, "role_permission_ids" => $role_permission_ids ]); } }
二、因爲基礎的增長改查都會編寫。在這裏寫set模板渲染
set.php在view中的role目錄,代碼以下:yii2
<div class="row"> <form class="form-horizontal tasi-form" method="POST" action="<?= Url::to('/role/set') ?>"> <div class="form-group"> <label class="col-sm-2 control-label col-lg-2" for="inputSuccess">角色</label> <div class="col-lg-10"> <?php if( $permissions ):?> <?php foreach( $permissions as $permission ):?> <div class="checkbox"> <label> <input type="checkbox" name="permission_ids[]" value="<?=$permission['id'];?>" <?php if( in_array( $permission['id'] ,$role_permission_ids ) ):?> checked <?php endif;?> /> <?=$permission['title'];?> </label> </div> <?php endforeach;?> <?php endif;?> <input type="hidden" name="id" value="<?=$role?$role['id']:0;?>"> <button type="submit" class="btn btn-default">Submit</button> </div> </div> </form> </div>
給三劍客增長、修改、刪除的核心代碼已經結束
5、基礎控制器的編寫:
實現辨別是否有權限訪問要訪問的頁面
BaseControllerapp
<?php namespace app\controllers; use Yii; use yii\filters\AccessControl; use yii\web\Controller; use yii\filters\VerbFilter; use app\models\Permission; use app\models\RolePermission; use app\models\User; use app\models\UserRole; use yii\helpers\Url; class BaseController extends Controller { protected $allowAllAction = [ 'site/login', ]; public $ignore_url = [ 'test/forbidden' , 'user/login' ]; public $privilege_urls = [];//保存有效的權限連接 // 本系統全部頁面都是須要登陸以後才能訪問的, 在框架中加入統一驗證方法 public function beforeAction($action) { $login_status = $this->checkLoginStatus(); if ( !$login_status && !in_array( $action->uniqueId,$this->allowAllAction ) ) { $this->redirect( "/site/login" );//返回到登陸頁面 return false; } // * // * 判斷權限的邏輯是 // * 取出當前登陸用戶的所屬角色, // * 在經過角色 取出 所屬 權限關係 // * 在權限表中取出全部的權限連接 // * 判斷當前訪問的連接 是否在 所擁有的權限列表中 //判斷當前訪問的連接 是否在 所擁有的權限列表中 if( !$this->checkPrivilege( $action->getUniqueId() ) ){ $this->redirect( "/test/forbidden"); return false; } return true; } //檢查是否有訪問指定連接的權限 public function checkPrivilege( $url ){ //若是是超級管理員 也不須要權限判斷,這裏能夠根據本身須要更改 if( Yii::$app->user->identity->id == 1 ){ return true; } //有一些頁面是不須要進行權限判斷的 if( in_array( $url,$this->ignore_url ) ){ return true; } return in_array( $url, $this->getRolePrivilege( ) ); } /* * 獲取某用戶的全部權限 * 取出指定用戶的所屬角色, * 在經過角色 取出 所屬 權限關係 * 在權限表中取出全部的權限連接 */ public function getRolePrivilege($uid = 0){ if( !$uid){ $uid = Yii::$app->user->identity->id; } if( !$this->privilege_urls ){ $role_ids = UserRole::find()->where([ 'uid' => $uid ])->select('role_id')->asArray()->column(); if( $role_ids ){ //在經過角色 取出 所屬 權限關係 $permission_ids = RolePermission::find()->where([ 'role_id' => $role_ids ])->select('permission_id')->asArray()->column(); //在權限表中取出全部的權限連接 $list = Permission::find()->where([ 'id' => $permission_ids ])->all(); $urls = []; if( $list ){ foreach( $list as $_item ){ $tmp_urls = @json_decode( $_item['urls'],true ); $urls[] = $tmp_urls; } $this->privilege_urls = array_merge( $this->privilege_urls,$urls ); } } } return $this->privilege_urls ; } //驗證登陸是否有效,返回 true or false protected function checkLoginStatus(){ if (Yii::$app->user->isGuest){ return false; } return true; } public function request($key, $def = false) { $result = $def; if(isset($key)) { $request = Yii::$app->getRequest(); if($request->isGet) { $result = $request->get($key, $def); }else if($request->isPost) { $result = $request->post($key, $def); } } return $result; } }
總體代碼沒有準備,若有須要能夠留言,準備後會將連接寫在這裏。框架