以前有个朋友问我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"); }
这样再添加用户的时候,就能够指定规则,进而实现对更加高级的指定权限
到这里,基本完成了用户建立,权限分配,及规则指定,但愿能够帮到你们~~