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; } }
总体代码没有准备,若有须要能够留言,准备后会将连接写在这里。框架