1.项目配置
这里说明的rbac使用的是DB ,所以打开config中main.php文件,在components里加入下面代码
'components' => [
'authManager' => [
'class' => 'yii\rbac\DbManager',//使用DB 数据更安全
// 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}}',
'defaultRoles' => ['default'],
],
]
2.通过yii命令 创建rbac数据表 并创建表对应 model
yii2提供 rbac数据表的创建(文件位置:vendor/yiisoft/yii2/rbac/migrations/schema-sqlite.sql),打开app/console/config/main.php 添加
'components' => [
'authManager' => [
'class' => 'yii\rbac\DbManager',//使用DB 数据更安全
// 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}}',
],
],
在项目根目录下 打开cmd 输入:
$ ./yii migrate --migrationPath=@yii/rbac/migrations
执行中提示是否执行,输入yes即可,执行成功后查看数据库增加四张表即表示成功
之后浏览器 输入 projecturl(项目url)/index.php?r=gii,选择model 创建四张权限表对应的model
3.创建用户角色
a.创建rabc控制器 RbacController.php 并打开
<?php
namespace backend\controllers;
use Yii;
use yii\web\Controller;
class RbacController extends CommonController
{
public function actionCreaterole()
{
//提交操作
if (Yii::$app->request->isPost) {
$auth = Yii::$app->authManager;//拿取权限角色
$role = $auth->createRole(null);//role 名称先赋值为空
$post = Yii::$app->request->post();
//name 和 description 不能为空
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)) { //操作表为 auth_item
Yii::$app->session->setFlash('success', '添加成功');
}
}
return $this->render('_createitem');
}
}
b.创建view 在app\backend\views\rbac\_createitem.php 并打开
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use common\models\Product;
use yii\bootstrap\ActiveForm;
/* @var $this yii\web\View */
/* @var $searchModel common\models\ProductSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */
$this->title = '添加角色';
$this->params['breadcrumbs'][] = ['label' => '角色管理', 'url' => ['rbac/roles']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="createitem-index">
<div class="container">
<?php
if (Yii::$app->session->hasFlash('info')) {
echo Yii::$app->session->getFlash('info');
}
$form = ActiveForm::begin([
'options' => [
'class' => 'form-horizontal',
'enctype' => 'multipart/form-data'
],//form 表单样式
'fieldConfig' => [
'options' => [
'tag'=>'span'
],
'template' => '{label}{input}{error}'
],
]);
?>
<div class="row">
<div class="col-md-6">
<?php echo Html::label('名称', null). Html::textInput('description', '', ['class' => 'form-control']); ?>
</div>
<div class="col-md-6">
<?php echo Html::label('标识', null). Html::textInput('name', '', ['class' => 'form-control']); ?>
</div>
</div>
<div class="row">
<div class="col-md-6">
<?php echo Html::label('规则名称', null). Html::textInput('rule_name', '', ['class' => 'form-control']); ?>
</div>
</div>
<div class="row">
<div class="col-md-12">
<?php echo Html::label('数据', null). Html::textarea('data', '', ['class' => 'form-control']); ?>
</div>
</div>
<div class="row">
<div class="col-md-12">
<?= Html::submitButton('创建' , ['class' => 'btn btn-success']) ?>
</div>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
c.创建角色 查看{{%auth_item}}表是否有添加数据
4.显示角色列表
a.打开 backend/controllers/RbacController.php 添加方法 actionIndex()
use backend\models\BsellerAuthItem;
use yii\data\Pagination;
.....
class RbacController extends Controller{
......
//角色列表
public function actionIndex()
{
$query = BsellerAuthItem::find()->where('type = 1')->orderBy('created_at desc');
$count = $query->count(); //数据总个数
$pageSize = Yii::$app->params['pageSize']['defaultPageSize']; //获取 config/params.php 中设置的页数
$pager = new Pagination(['totalCount' => $count, 'pageSize' => $pageSize]); //分页
$models = $query->offset($pager->offset)->limit($pager->limit)->all(); //获取分页后的数据
return $this->render('index', [
'pager' => $pager,
'models' => $models,
]);
}
}
创建并打开backend/views/rbac/index.php
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use common\models\PurchaseOffer;
/* @var $this yii\web\View */
/* @var $searchModel common\models\PurchaseSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */
$this->title = '角色列表';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="purchase-index">
<p>
<?= Html::a('添加角色', ['createrole'], ['class' => 'btn btn-success']) ?>
</p>
<div class="row">
<div class="col-md-12">
<table class="table table-hover table-bordered">
<thead>
<tr>
<tr>
<th class="">
名称
</th>
<th>
标识
</th>
<th class="">
规则名称
</th>
<th class="">
创建时间
</th>
<th class="align-right">
操作
</th>
</tr>
</tr>
</thead>
<tbody>
<!-- row -->
<?php foreach($models as $model): ?>
<tr class="">
<td>
<?= $model['description'] ?>
</td>
<td>
<?= $model['name'] ?>
</td>
<td>
<?= $model['rule_name'] ?>
</td>
<td>
<?= date("Y-m-d h:i", $model['created_at']) ?>
</td>
<td class="align-right">
<?=Html::a('分配权限', ['view', 'name' => $model['name']])?> |
<?=Html::a('更新', ['view', 'name' => $model['name']])?> |
<?=Html::a('删除', ['view', 'name' => $model['name']])?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="pagination pull-right">
<!-- 分页组件 prevPageLabel上一页 nextPageLabel下一页-->
<?php echo yii\widgets\LinkPager::widget(['pagination' => $pager, 'prevPageLabel' => '‹', 'nextPageLabel' => '›']); ?>
</div>
</div>
</div>
5.console 命令行一键获取所有权限
创建并打开console/controllers/RabcController.php
<?php
namespace console\controllers;
use Yii;
use yii\console\Controller;
/**
* CommentController implements the CRUD actions for CommentProduct model.
*/
class RbacController extends Controller
{
public function actionInit()
{
$trans = Yii::$app->db->beginTransaction();
try {
$dir = dirname(dirname(dirname(__FILE__))). '/backend/controllers';
$controllers = glob($dir. '/*');
$permissions = [];
foreach ($controllers as $controller) {
$content = file_get_contents($controller);
preg_match('/class ([a-zA-Z]+)Controller/', $content, $match);
$cName = $match[1];
$permissions[] = strtolower($cName. '/*');
preg_match_all('/public function action([a-zA-Z_]+)/', $content, $matches);
foreach ($matches[1] as $aName) {
$permissions[] = strtolower($cName. '/'. $aName);
}
}
$auth = Yii::$app->authManager;
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";
}
}
}
在项目根目录下 打开cmd 输入:
$ ./yii rbac/init
import success
执行成功后 进入数据库查看item看是否导入成功(接口列表 在item表里面 type = 2)
6.角色分配权限子节点和角色子节点
a.打开 backend/controllers/RbacController.php 添加方法 actionAssignitem($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', '分配成功');
return $this->redirect(['rbac/index']);
}
}
//获取对应角色 下的权限
$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]);
}
b.创建并打开 backend\models\Rbac.php
<?php
namespace backend\models;
use yii\db\ActiveRecord;
use Yii;
class Rbac extends ActiveRecord
{
//获取 接口节点 数组
public static function getOptions($data, $parent)
{
$return = [];
foreach ($data as $obj) {
//为能为空&&不能为角色自身&&是否能够分配
if (!empty($parent) && $parent->name != $obj->name && Yii::$app->authManager->canAddChild($parent, $obj)) {
$return[$obj->name] = $obj->description;
}
}
return $return;
}
//添加权限子节点
public static function addChild($children, $name)
{
$auth = Yii::$app->authManager;
//拿到角色
$itemObj = $auth->getRole($name);
if (empty($itemObj)) {
return false;
}
//开启事务
$trans = Yii::$app->db->beginTransaction();
try {
//先清除权限
$auth->removeChildren($itemObj);
//循环添加权限
foreach ($children as $item) {
//如果是对象 就遍你对象下的权限否则直接添加
$obj = empty($auth->getRole($item)) ? $auth->getPermission($item) : $auth->getRole($item);
$auth->addChild($itemObj, $obj);
}
$trans->commit();
} catch(\Exception $e) {
$trans->rollback();
return false;
}
return true;
}
//获取对应角色 下的权限
public static function getChildrenByName($name)
{
if (empty($name)) {
return [];
}
$return = [];
$return['roles'] = [];
$return['permissions'] = [];
$auth = Yii::$app->authManager;
$children = $auth->getChildren($name);
if (empty($children)) {
return $return;
}
foreach ($children as $obj) {
//如果是1 为角色
if ($obj->type == 1) {
$return['roles'][] = $obj->name;
} else { //如果是2 则为权限
$return['permissions'][] = $obj->name;
}
}
return $return;
}
}
c.创建权限分配页面,创建并打开backend\views\rbac\_assignitem.php
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use common\models\Product;
use yii\bootstrap\ActiveForm;
/* @var $this yii\web\View */
/* @var $searchModel common\models\ProductSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */
$this->title = '分配权限';
$this->params['breadcrumbs'][] = ['label' => '角色列表', 'url' => ['rbac/index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="createitem-index">
<div class="container">
<?php
if (Yii::$app->session->hasFlash('info')) {
echo Yii::$app->session->getFlash('info');
}
$form = ActiveForm::begin([
'options' => [
'class' => 'form-horizontal',
'enctype' => 'multipart/form-data'
],//form 表单样式
'fieldConfig' => [
'options' => [
'tag'=>'span'
],
'template' => '{label}{input}{error}'
],
]);
?>
<div class="row">
<div class="col-md-12">
<h2> <?php echo Html::label('角色名称', null). Html::encode($parent); ?> </h2>
</div>
</div>
<div class="row">
<div class="col-md-12">
<?php echo Html::label('角色子节点', null). Html::checkboxList('children', $children['roles'], $roles); ?>
</div>
</div>
<div class="row">
<div class="col-md-12">
<?php echo Html::label('权限子节点', null). Html::checkboxList('children', $children['permissions'], $permissions); ?>
</div>
</div>
<div class="row">
<div class="col-md-12">
<?= Html::submitButton('创建' , ['class' => 'btn btn-success']) ?>
</div>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
d.跑通测试: 进入权限列表页,选择一条数据 点击进入分配权限,进入后可以分配角色(系统将把角色下的权限分配给此操作对象),也可以选择复选框进行制定分配权限,创建完,打开数据表 {{%auth_item_child}},查看是否成功分配权限.
7.后台管理员授权
a.打开管理员controller层,本项目地址为 backend\controllers\AdminController.php,添加方法 actionAssign
<?php
.......
use backend\models\Rbac;
.......
.......
//管理员授权
public function actionAssign($adminid)
{
$this->layout = "main";
$adminid = (int)$adminid;
if (empty($adminid)) {
throw new \Exception('参数错误');
}
$admin = Admin::findOne($adminid);
if (empty($admin)) {
throw new \yii\web\NotFoundHttpException('admin not found');
}
if (Yii::$app->request->isPost) {
$post = Yii::$app->request->post();
$children = !empty($post['children']) ? $post['children'] : [];
if (Rbac::grant($adminid, $children)) {
Yii::$app->session->setFlash('info', '授权成功');
}
}
$auth = Yii::$app->authManager;
//获取所有角色
$roles = Rbac::getOptions($auth->getRoles(), null);
//获取所有授权
$permissions = Rbac::getOptions($auth->getPermissions(), null);
//获取用户 的授权/角色
$children = Rbac::getChildrenByUser($adminid);
return $this->render('_assign', ['children' => $children, 'roles' => $roles, 'permissions' => $permissions, 'admin' => $admin->adminuser]);
}
b.修改backend/models/Rbac.php 中getOptions($data,$parent)方法,并且添加多个管理员授权方法
//修改处
//获取 接口节点 数组
public static function getOptions($data, $parent)
{
$return = [];
foreach ($data as $obj) {
//为能为空&&不能为角色自身&&是否能够分配
if (!empty($parent) && $parent->name != $obj->name && Yii::$app->authManager->canAddChild($parent, $obj)) {
$return[$obj->name] = $obj->description;
}
//为管理员授权
if(is_null($parent)){
$return[$obj->name] = $obj->description;
}
}
return $return;
}
//添加处
//获取管理员已有的 角色/授权
private static function _getItemByUser($adminid, $type)
{
// $func 为 函数名称为
$func = 'getPermissionsByUser';
if ($type == 1) {
$func = 'getRolesByUser';
}
$data = [];
$auth = Yii::$app->authManager;
$items = $auth->$func($adminid);
foreach ($items as $item) {
$data[] = $item->name;
}
return $data;
}
//获取管理员 权限
public static function getChildrenByUser($adminid)
{
$return = [];
//获取管理员分配到的角色
$return['roles'] = self::_getItemByUser($adminid, 1);
//获取管理员分配到的权限
$return['permissions'] = self::_getItemByUser($adminid, 2);
return $return;
}
//操作{{%auth_assignment}}
public static function grant($adminid, $children)
{
$trans = Yii::$app->db->beginTransaction();
try {
$auth = Yii::$app->authManager;
//先清除授权
$auth->revokeAll($adminid);
foreach ($children as $item) {
//如果角色为空(不为角色)?返回角色 : 返回权限
$obj = empty($auth->getRole($item)) ? $auth->getPermission($item) : $auth->getRole($item);
$auth->assign($obj, $adminid);
}
$trans->commit();
} catch (\Exception $e) {
$trans->rollback();
return false;
}
return true;
}
c.新建管理员授权试图,创建并修改 backend\views\admin\_assign.php
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use common\models\Product;
use yii\bootstrap\ActiveForm;
/* @var $this yii\web\View */
/* @var $searchModel common\models\ProductSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */
$this->title = '授权';
$this->params['breadcrumbs'][] = ['label' => '管理员列表', 'url' => ['admin/index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="createitem-index">
<div class="container">
<?php
if (Yii::$app->session->hasFlash('info')) {
echo Yii::$app->session->getFlash('info');
}
$form = ActiveForm::begin([
'options' => [
'class' => 'form-horizontal',
'enctype' => 'multipart/form-data'
],//form 表单样式
'fieldConfig' => [
'options' => [
'tag'=>'span'
],
'template' => '{label}{input}{error}'
],
]);
?>
<div class="row">
<div class="col-md-12">
<h2>
<?php echo Html::label('管理员', null). Html::encode($admin); ?>
</h2>
</div>
</div>
<div class="row">
<div class="col-md-12">
<?php echo Html::label('角色', null). Html::checkboxList('children', $children['roles'], $roles); ?>
</div>
</div>
<div class="row">
<div class="col-md-12">
<?php echo Html::label('权限', null). Html::checkboxList('children', $children['permissions'], $permissions); ?>
</div>
</div>
<div class="row">
<div class="col-md-12">
<?= Html::submitButton('创建' , ['class' => 'btn btn-success']) ?>
</div>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
b.验证步骤 创建完查看 {{%auth_assignment}} 表中item_name 为 权限名 or 角色名 ,user_id 为管理员id
8.后台管理员权限认证
a.backend/controllers里定义一个父类控制层 CommonController.php ,其他控制层都继承如:
......
class RbacController extends CommonController{
......
}
b.修改 backend/controllers/CommonController.php
<?php
namespace backend\controllers;
use Yii;
use yii\web\Controller;
/**
* Site controller
*/
class CommonController extends Controller
{
//管理员权限认证
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;
}
public function init()
{
// if (Yii::$app->session['admin']['isLogin'] != 1) {
// return $this->redirect(['/admin/public/login']);
// }
}
}
其中$controller为请求指向的控制器名称,$actionName为方法名,Yii::$app->admin 为用户登录认证后调用的方法(这里对yii2 用户登录不清楚的盆友请先了解 yii2用户登录认证体系).
9.根据权限显示菜单
a.创建和修改backend\config\adminmenu.php
<?php
return [
'adminmenu' =>[
['label' => '首页', 'url' => 'site/index', 'module' => 'site', 'icon' => 'fa-home'],
['label' => '管理员管理', 'url' => '#', 'module' => 'admin', 'icon' => 'fa-home', 'submenu' => [
['label' => '管理员列表', 'url' => 'index']
]],
['label' => '权限管理', 'url' => '#', 'module' => 'rbac', 'icon' => 'fa-home', 'submenu' => [
['label' => '权限列表', 'url' => 'index']
]],
]
];
b.添加adminmenu.php 添加到项目参数里,修改backend\config\main.php
<?php
$params = array_merge(
require(__DIR__ . '/../../common/config/params.php'),
require(__DIR__ . '/../../common/config/params-local.php'),
require(__DIR__ . '/params.php'),
require(__DIR__ . '/params-local.php'),
require(__DIR__ . '/adminmenu.php')
);
........
c.根据权限遍历菜单,因为每个后台项目管理用的菜单样式不同,所以这里需要理解,勿照搬照抄,根据项目进行改动
<ul class="nav nav-pills nav-stacked nav-quirk">
<?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 !empty($menu['submenu']) ? 'nav-parent ' : ''; echo $controller == $menu['module'] ? 'active ' : ''; echo $show; ?>">
<a href="<?php echo $menu['url'] == '#' ? '#' : yii\helpers\Url::to([$menu['url']]); ?>">
<i class="fa <?php echo $menu['icon'] ?>"></i>
<span><?php echo $menu['label']; ?></span>
</a>
<?php if (!empty($menu['submenu'])) : ?>
<ul class="children <?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 class="<?php echo $action == $sub['url'] ? 'active ' : ''; echo $show; ?>">
<a href="<?php echo yii\helpers\Url::to([$menu['module']. '/'. $sub['url']]); ?>"><?php echo $sub['label'] ?></a>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</li>
<?php
}
?>
</ul>
结束