yii2系列(二)菜单和RBAC权限管理

本文目的

接着上一篇文章yii2系列(一)项目搭建,以及常用组件的安装配置,继续配置yii2的各种组件
包括权限管理,菜单等。

环境要求

按照yii2系列(一)项目搭建,以及常用组件的安装配置配置完毕。

完整步骤

参考
yii2搭建完美后台并实现rbac权限控制实例教程
yii2权限控制rbac之rule详细讲解
yii2-admin 插件使用简要教程
yii2 rbac权限控制之菜单menu详细教程
Yii2全面解析之权限管理RBAC
yii2搭建完美后台并实现rbac权限控制实例教程
Yii2实用基础学习笔记(十):RBAC

RBAC简介

RBAC,即基于角色的访问控制(Role-Based Access Control)。

RBAC 支持三个著名的安全原则:最小权限原则,责任分离原则和数据抽象原则。

Yii2的RBAC核心文件在@vendoryiisoftyii2rbac目录下,数据表的创建信息在该目录的 migrations` 目录下。

许可(Permission):包括许可标识、许可名称、受控对象、操作标识等。给出了受控对象与操作算子的对应关系。

角色(Role):包括角色标识、角色名称、角色基数、角色可用标识等。是系统角色集,由系统管理员定义角色。

用户(User):包括用户标识、用户姓名、用户登录密码等。是系统中的个体用户集,随用户的添加与删除动态变化。

规则(Rule):与一个角色或者权限关联。一个规则用一段代码代表, 规则的执行是在检查一个用户是否满足这个角色或者权限时进行的。

举个例子,下面是角色和用户的模拟设置:

//用户
[
    管理员admin =>[
        管理员角色
        用户角色
        其他角色
    ]
    普通用户 =>[
        用户角色
        其他角色
    ]
]
//角色
[
    管理员角色=>[
        查看用户相关许可=>[
            '/admin/user/index',
            '/admin/user/view'
        ]
        分配权限相关许可=>[
            '/admin/assignment/index',
            '/admin/assignment/vieww'
        ]
    ]
    用户角色=>[
        登陆登出相关许可=>[
            '/user/login',
            '/site/logout'
        ]
    ]
    其他角色=>[
        ...
    ]
    游客角色=>[
        游客默认路由=>'/user/login'
    ]
]

前期准备

显示admin管理菜单

第一种方法:

首先,我们把下面这一段代码放到\frontend\themes\adminlte\layouts\left.php中的<section class="sidebar">标签中,放在哪无所谓。添加这个是为了方便临时访问。

<ul class="sidebar-menu">
    <li class="">
        <a href="#">
            <i class="fa fa-circle-o"></i>
            <span>权限管理</span>
            <span class="pull-right-container"><i class="fa fa-angle-left pull-right"></i></span>
        </a>
        <ul class="treeview-menu" style="display: none;">
            <li><a href="/admin/assignment/index"><i class="fa fa-circle-o"></i>  <span>分配</span></a></li>
            <li class=""><a href="/admin/permission/index"><i class="fa fa-circle-o"></i>  <span>权限列表 </span></a></li>
            <li><a href="/admin/user/index"><i class="fa fa-circle-o"></i>  <span>用户列表</span></a></li>
            <li><a href="/admin/menu/index"><i class="fa fa-circle-o"></i>  <span>菜单列表</span></a></li>
            <li><a href="/admin/rule/index"><i class="fa fa-circle-o"></i>  <span>规则列表</span></a></li>
            <li><a href="/admin/role/index"><i class="fa fa-circle-o"></i>  <span>角色列表</span></a></li>
            <li><a href="/admin/route/index"><i class="fa fa-circle-o"></i>  <span>路由列表</span></a></li>
        </ul>
    </li>
</ul>

添加完上面的代码刷新页面左侧会出现类似下面图片的菜单,可以方便的访问admin的管理功能。

微信截图_20170703140231.png

第二种方法:
其实还有另一种添加菜单的方法,但是那种方法需要用admin自带的layout。
打开\frontend\config\main.php文件,在对应位置改成下面的代码

//额外安装的模块
'modules' => [
    //加载user
    'user' => [
        'class' => 'dektrium\user\Module',
    ],
    //加载admin
    'admin' => [
        'class' => 'mdm\admin\Module',
        'layout' => 'left-menu',//yii2-admin的导航菜单
    ],
],

添加了'layout' => 'left-menu'之后就可以看到admin自带的菜单了。
点击帮助显示默认页面,点击应用回到网站layout。
微信截图_20170703140642.png

微信截图_20170703140725.png

创建测试文件

使用gii创建一个controller和view文件夹,用来测试我们的权限,我这里起的名字是RbactestController
微信截图_20170630145313.png

我们在\frontend\controllers\RbactestController.php中添加四个方法,用来测试。

<?php

namespace frontend\controllers;

class RbactestController extends \yii\web\Controller
{
    public function actionIndex()
    {
        return $this->render('index');
    }
    public function actionAdd()
    {
        return $this->render('index');
    }
    public function actionDelete()
    {
        return $this->render('index');
    }
    public function actionUpdate()
    {
        return $this->render('index');
    }
    public function actionSelect()
    {
        return $this->render('index');
    }
}

\frontend\views\rbactest\index.php中添加一个echo用来表示当前执行的方法。

<?php
/* @var $this yii\web\View */
//输出当前路由
echo '<h1>'.$this->context->module->requestedRoute.'</h1>';
?>

我添加完之后尝试访问/rbactest,发现返回提示您没有执行此操作的权限。,现在我们尝试添加菜单和许可来控制权限。

创建菜单,设置权限

添加路由

在左边菜单找到路由列表,将需要分配的路由,添加到右边。
我添加的路由为,在中间可以看到我添加的5个rbactest的路由

/admin/assignment/assign
/admin/assignment/index
/admin/assignment/revoke
/admin/assignment/view
/admin/default/index
/admin/menu/create
/admin/menu/delete
/admin/menu/index
/admin/menu/update
/admin/menu/view
/admin/permission/assign
/admin/permission/create
/admin/permission/delete
/admin/permission/index
/admin/permission/remove
/admin/permission/update
/admin/permission/view
/admin/role/assign
/admin/role/create
/admin/role/delete
/admin/role/index
/admin/role/remove
/admin/role/update
/admin/role/view
/admin/route/assign
/admin/route/create
/admin/route/index
/admin/route/refresh
/admin/route/remove
/admin/rule/create
/admin/rule/delete
/admin/rule/index
/admin/rule/update
/admin/rule/view
/admin/user/activate
/admin/user/change-password
/admin/user/delete
/admin/user/index
/admin/user/login
/admin/user/logout
/admin/user/request-password-reset
/admin/user/reset-password
/admin/user/signup
/admin/user/view
/debug/default/db-explain
/debug/default/download-mail
/debug/default/index
/debug/default/toolbar
/debug/default/view
/gii/default/action
/gii/default/diff
/gii/default/index
/gii/default/preview
/gii/default/view
/rbactest/add
/rbactest/delete
/rbactest/index
/rbactest/select
/rbactest/update
/site/captcha
/site/logout
/user/admin/assignments
/user/admin/block
/user/admin/confirm
/user/admin/create
/user/admin/delete
/user/admin/index
/user/admin/info
/user/admin/resend-password
/user/admin/switch
/user/admin/update
/user/admin/update-profile
/user/profile/index
/user/profile/show
/user/recovery/*
/user/recovery/request
/user/recovery/reset
/user/registration/confirm
/user/registration/connect
/user/registration/register
/user/registration/resend
/user/security/auth
/user/security/login
/user/security/logout
/user/settings/account
/user/settings/confirm
/user/settings/delete
/user/settings/disconnect
/user/settings/networks
/user/settings/profile

添加权限

权限管理->权限列表->新增权限
按照下面的列表添加权限,每个路由都附带上index路由(其实index没什么用,因为是没办法在菜单中直接进入index的)

rbac add=>[
    /rbactest/index
    /rbactest/add
]
rbac delete=>[
    /rbactest/index
    /rbactest/delete
]
rbac update=>[
    /rbactest/index
    /rbactest/update
]
rbac select=>[
    /rbactest/index
    /rbactest/select
]

微信截图_20170630173811.png

添加菜单

权限管理->菜单列表->新增菜单
首先添加一个叫做rbac_test的顶级菜单,也就是不写父级名称和路由的,剩下四个菜单按照类似下面的格式写到刚才添加的顶级menu里。

微信截图_20170630180212.png

微信截图_20170630185308.png

添加角色

设置了权限还不够,需要在权限和用户中间加上一层角色。
因为有一些权限是共享的,为了不重复给某一个用户添加权限,需要添加角色。

微信截图_20170703135300.png

用户角色里面只添加了一个叫做用户基础的权限,里面包括了基本的权限,登出、主页等。
系统管理员角色里面添加了两个权限,权限管理用户基础,把admin路由加到了权限管理里面。

给账号添加权限

可以看到我已经给moozik账号分配了用户系统管理员两个角色,又添加了两个权限分别是add和del。
也就是说虽然yii的rbac支持使用用户->角色->权限->路由的方法添加权限到账户,但是可以跳过其中的角色直接给账户分配权限
微信截图_20170630185545.png

添加完成之后将下面代码添加到\frontend\themes\adminlte\layouts\left.php,并将同名方法注释掉,如果你在菜单也添加了admin权限管理的路由,那就可以把上面我们临时添加的菜单删掉了。

        <?=dmstr\widgets\Menu::widget( [
        'options' => ['class' => 'sidebar-menu'],
        'items' => MenuHelper::getAssignedMenu(Yii::$app->user->id),
        ] );?>

添加完成,刷新页面,左侧菜单已经有了刚才添加的两个权限对应的菜单。

微信截图_20170702003505.png

rbac add权限对应add菜单
rbac del权限对应delete菜单

我起名字的能力比较差,希望你没有被绕晕。
我的理解是这样,权限和路由是一对多的关系,目录跟路由是一对一的关系。
猜测生成左侧目录的过程:

  1. 获取用户moozik的角色和权限
  2. 获取用户moozik可访问的所有路由
  3. 获取用户moozik可访问路由对应的所有目录

进阶用法

权限判断

打开\frontend\views\rbactest\index.php,在其中加入下面的代码。

<h4>你的权限:</h4>
<ul>
<?php
    //权限列表
    $permission=['rbac add','rbac del','rbac update','rbac select'];
    foreach($permission as $item){
        //检查当前用户是否有权限
        if(Yii::$app->user->can($item)){
            echo '<li>'.$item.'</li>';
        }
    }
?>
</ul>

访问/rbactest,可以看到使用Yii::$app->user->can(permission)可以判断当前用户的权限。
某些场景下,我们需要在一个功能中区分权限,比如一个按钮或者一段数据是否显示,这个时候就可以使用这个方法进行判断。
微信截图_20170702033423.png

当然不只是判断权限,也可以增删改查权限信息,这样就可以实现更加复杂的权限控制。然而yii给我们准备了更细的权限控制。

规则文件

关于规则控制网上的资料不太多,可以参考yii2权限控制rbac之rule详细讲解

在我们添加权限的时候,页面中有一个规则名称,这个是可为空的选项,也就是说是更进一步的控制。

举个例子:

5个管理员管理一个网站,我们希望他们的文章互不干扰,A的文章自己写完了别人不能改不能删,只能自己改自己删。

这个时候上面写的那个权限判断就没用了,因为这几个人都有修改文章那个路由的访问权限,而需要用文章创建人去判断。


开始我们的实验。

为了方便测试,我在数据库中复制了我的moozik账号,粘贴成moozik2方便测试两个账号。

我们准备让moozik只能操作单数id,moozik2只能操作复数id,如果没有id也可以访问。

添加下面的代码到\frontend\views\rbactest\index.php,用来显示当前的id。

<h2>参数:<?=Yii::$app->request->get('id')?></h2>

保存下面的代码到\frontend\components\RbactestRule.php

<?php
namespace frontend\components;
use Yii;
use yii\rbac\Rule;
class RbactestRule extends Rule
{
    public $name = 'rbactest';
    public function execute($user, $item, $params)
    {
        // 这里先设置为false,逻辑上后面再完善
        return false;
    }
}

按照图片中的样子将规则文件添加到任意一个权限中。

微信截图_20170702042847.png

刷新页面,发现add目录是有的,但是尝试打开add页面发现返回没有权限,这就说明添加的规则文件生效了,规则文件中是无脑返回false的,所以不可能通过权限检测。现在我们完善规则文件。

<?php
namespace frontend\components;
use Yii;
use yii\rbac\Rule;

class RbactestRule extends Rule
{
    public $name = 'rbactest';
    public function execute($user, $item, $params)
    {
        $id = Yii::$app->request->get('id');
        $username = Yii::$app->user->identity->username;

        if(empty($id)){
            return true;
        }

        if($id % 2 === 0 and $username === 'moozik2'){
            return true;
        }else if($id % 2 !== 0 and $username === 'moozik'){
            return true;
        }
        return false;
    }
}

经过尝试,moozik账号只能访问单数id。

我给moozik2添加了rbactest里面所有的权限,并且也是只能访问指定的复数id。

当然在真实情况中肯定是去数据库查询,或者其他一些操作。execute()方法传进来的$user是用户id,可以方便的进行权限检查。

微信截图_20170702052251.png

最后修改:2017 年 07 月 19 日 05 : 32 PM

发表评论