首先需要安装yii-admin
composer require mdmsoft/yii2-admin "~2.0"
然后配置yii-admin
'modules' => [
'admin' => [
'class' => 'mdm\admin\Module',
'controllerMap' => [
'assignment' => [
'class' => 'mdm\admin\controllers\AssignmentController',
'userClassName' => 'common\models\Admin',
],
],
//'layout' => 'left-menu',
//'layout' => '@backend/views/layouts/main.php',
'menus' => [
'assignment' => [
'label' => 'Grand Access', // change label
],
//'route' => null, // disable menu route
],
]
],
'as access' => [
'class' => 'mdm\admin\components\AccessControl',
'allowActions' => [
'site/*',
'admin/*',
]
],
创建相关表
php yii migrate --migrationPath=@mdm/admin/migrations
php yii migrate --migrationPath=@yii/rbac/migrations
访问地址 xxx.com/admin/route/index
相关表说明
menu // 菜单表,对应后台左侧菜单
auth_rule //规则,规则类名
auth_item_child //角色对应的权限,parent角色,child权限名
auth_item //角色|权限表,type=1角色,type=2权限
auth_assignment //角色与用户对应关系表
到这里权限基本可以用了,但是这个只有开发人员可以看懂,普通操作人员是没法操作的,所以我们需要优化,让普通操作人员也能操作。
首先,在auth_item表添加3个字段
title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`sort` int(11) DEFAULT '0' COMMENT '排序',
`auth_parent` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`is_permission` tinyint(4) DEFAULT '0' COMMENT '0:表示参与权限管理,1:表示默认给与权限,比如一些Ajax,4:表示只有超级管理员才有的权限',
title表示前端页面显示标题
sort表示排序
auth_parent表示层级关系, 如/user/*表示父级, /user/index表示子级
is_permission表示是否参与权限管理
然后就是角色管理。
使用php yii gii/model 命令分别生成4个表的模型,并建立角色控制器,如AuthPermissionController.php
在这个控制器中,我们需要新建角色,并分配权限,新建角色很简单,就是create,update,比较麻烦的是权限。
首先我们需要初始化标题,当然也可以通过create,update手动初始化,这样比较灵活,这里使用自动初始化。
private function makeInfo($items) {
// 修正auth_parent、 index、rule_name
foreach($items as $key => $val) {
if(empty($val->title)) {
$route = $val->name;
// 路由格式: /permission/index
// 路由格式: /permission/index
$route2 = str_replace('-', '_', $route);
$routeArr = explode('/', $route2);
if(count($routeArr) > 1) {
$action = $routeArr[2];
$controllerName = Yii::t('backend', $routeArr[1]);
$parent = '';
$title = '';
if(isset($routeArr[3])) {
$controllerName = Yii::t('backend', $routeArr[1]) . Yii::t('backend', $routeArr[2]);
$actionName = Yii::t('backend', 'action_' . $routeArr[3]);
$parent = $routeArr[1] . '_' . $routeArr[2];
$title = $actionName;
if($routeArr[3] == '*') {
$actionName = '';
$title = $controllerName;
}
} else {
$actionName = Yii::t('backend', 'action_' . $routeArr[2]);
$parent = $routeArr[1];
$title = $actionName;
if($routeArr[2] == '*') {
$actionName = '';
$parent = '';
$title = $controllerName;
}
}
// 只有超级管理员才能操作的
$adminPermission = ['admin', 'manager', 'rule-permission', 'gii', 'debug', 'test'];
// 默认给与权限的
$allowPermission = ['dashboard', 'uploader'];
// is_permission 0:表示参与权限管理,1:表示默认给与权限,比如一些Ajax,4:表示只有超级管理员才有的权限
$isPermission = 0;
foreach($adminPermission as $ak => $av) {
$adminIndex = stripos($route, $av);
if($adminIndex !== false) {
$isPermission = 4;
}
}
foreach($allowPermission as $ak => $av) {
$adminIndex = stripos($route, $av);
if($adminIndex !== false) {
$isPermission = 1;
}
}
$val->title = $title;
$val->index = 1;
$val->is_permission = $isPermission;
$val->auth_parent = $parent;
$val->save();
}
}
}
}
然后是读取权限列表
private function treelist($items, $parent = '') {
$list = [];
foreach($items as $key => $val) {
if(empty($val->auth_parent)) {
$data['name'] = $val->name;
$data['title'] = $val->title;
$data['index'] = $val->index;
$data['auth_parent'] = $val->auth_parent;
$data['children'] = [];
$route2 = str_replace('-', '_', $val->name);
$routeArr = explode('/', $route2);
if(count($routeArr) > 1) {
$parent = '';
if(isset($routeArr[3])) {
$parent = $routeArr[1] . '_' . $routeArr[2];
} else {
$parent = $routeArr[1];
}
if(!empty($parent)) {
foreach($items as $k => $v) {
if($v->auth_parent == $parent) {
$sdata['name'] = $v->name;
$sdata['title'] = $v->title;
$sdata['index'] = $v->index;
$sdata['auth_parent'] = $v->auth_parent;
$data['children'][] = $sdata;
}
}
}
}
$list[] = $data;
}
}
return $list;
}
,接下来是保存权限
if(Yii::$app->request->isPost) {
$permissionsPost = Yii::$app->request->post('permission');
if(!empty($permissionsPost)) {
// 如果已经有权限,则不做处理
// 如果没有则添加
$newPermission = array_diff($permissionsPost, $permissions);
if($newPermission) {
foreach($newPermission as $key => $val) {
$authItemChildModel = new AuthItemChild();
$authItemChildModel->parent = $model->name;
$authItemChildModel->child = $val;
$authItemChildModel->save();
}
}
// 如果已有但传入的数据没有,则删除
$deletePermission = array_diff($permissions, $permissionsPost);
if($deletePermission) {
foreach($deletePermission as $key => $val) {
$authItem = AuthItem::find()->where(['name' => $val])->one();
if($authItem->is_permission == 0) {
AuthItemChild::deleteAll(['parent' => $model->name, 'child' => $val]);
}
}
}
// 默认给与权限
$allowPermission = ['/dashboard/*', '/uploader/*'];
foreach($allowPermission as $key => $val) {
$authItemChild = AuthItemChild::find()->where(['parent' => $model->name, 'child' => $val])->one();
if(empty($authItemChild)) {
$authItemChildModel = new AuthItemChild();
$authItemChildModel->parent = $model->name;
$authItemChildModel->child = $val;
$authItemChildModel->save();
}
}
return $this->redirect(['view', 'id' => $id]);
}
}
前端页面
<?php $form = ActiveForm::begin(); ?>
<div class="permission-list">
<?php
foreach($list as $key => $val) {
$checked = '';
if(in_array($val['name'], $permissions)) {
$checked = ' checked="checked" ';
}
?>
<div class="permission-item">
<div class="row">
<div class="col-md-2 parent">
<input type="checkbox" class="parent-permission" name="permission[]" value="<?= $val['name'] ?>" <?= $checked ?> /> <?= $val['title'] ?>
</div>
<div class="col-md-9 children">
<?php
if(isset($val['children'])) {
foreach($val['children'] as $k => $v) {
// 如果子路由在权限或者所有子路由(*)在权限,则选中
// 最后一个 / 如: /user/create
$lastIndex = strripos($v['name'], '/');
// 截取路由controller, 如:/user/
$controllerPath = substr($v['name'], 0, $lastIndex + 1);
// 链接*,表示全部子路由,如:/user/*
$controllerPath = $controllerPath . '*';
$schecked = '';
if(in_array($v['name'], $permissions) || in_array($controllerPath, $permissions)) {
$schecked = ' checked="checked" ';
}
?>
<span><input type="checkbox" class="child-permission" name="permission[]" value="<?= $v['name'] ?>" <?= $schecked ?> /> <?= $v['title'] ?></span>
<?php } } ?>
</div>
</div>
</div>
<?php } ?>
<div class="permission-submit">
<?= Html::submitButton(Yii::t('backend', 'save'), ['class' => 'btn btn-success']) ?>
</div>
</div>
<?php ActiveForm::end(); ?>
js
// 点击父权限,子权限全部选中
$('.permission-list .permission-item .parent-permission').each(function() {
$(this).on('change', function() {
$(this).parent().next().find('.child-permission').prop('checked', $(this).prop('checked'));
})
})
// 点击子权限,如果有一个没选中,父权限不选中,如果所有都选中,父权限选中
$('.permission-list .permission-item .child-permission').each(function() {
$(this).on('change', function() {
var isChecked = $(this).prop('checked');
if(isChecked) {
// 选中
// 判断是否全部选中
var isAllChecked = true;
var allChild = $(this).parent().siblings().find('.child-permission');
for(var i = 0; i < allChild.length; i++) {
if(!$(allChild[i]).prop('checked')) {
isAllChecked = false;
break;
}
}
if(isAllChecked) {
$(this).parent().parent().prev().find('.parent-permission').prop('checked', true);
}
} else {
// 不选中
$(this).parent().parent().prev().find('.parent-permission').prop('checked', false);
}
})
})
AuthPermissionController.php
use Yii;
use common\models\Auth\AuthRule;
use common\models\Auth\AuthItem;
use common\models\Auth\AuthItemChild;
use common\models\Auth\AuthAssignment;
use yii\data\ActiveDataProvider;
use backend\controllers\BackendController;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
/**
* PermissionController implements the CRUD actions for Permission model.
* est_auth_item 表需要添加字段auth_parent:默认0; index: 排序
*/
class RulePermissionController extends BackendController
{
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
],
];
}
/**
* Lists all Permission models.
* @return mixed
*/
public function actionIndex()
{
$dataProvider = new ActiveDataProvider([
'query' => AuthItem::find()->where(['type' => 1]),
]);
$authItems = AuthItem::find()->where(['type' => 2])->orderBy('index DESC')->all();
// 初始化标题
$this->makeInfo($authItems);
return $this->render('index', [
'dataProvider' => $dataProvider,
]);
}
/**
* Displays a single Order model.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionView($id)
{
$model = $this->findModel($id);
// 获取角色所有权限
$authItemChild = AuthItemChild::find()->where(['parent' => $model->name])->all();
$permissions = [];
if($authItemChild) {
foreach($authItemChild as $key => $val) {
$permissions[] = $val->child;
}
}
if(Yii::$app->request->isPost) {
$permissionsPost = Yii::$app->request->post('permission');
if(!empty($permissionsPost)) {
// 如果已经有权限,则不做处理
// 如果没有则添加
$newPermission = array_diff($permissionsPost, $permissions);
if($newPermission) {
foreach($newPermission as $key => $val) {
$authItemChildModel = new AuthItemChild();
$authItemChildModel->parent = $model->name;
$authItemChildModel->child = $val;
$authItemChildModel->save();
}
}
// 如果已有但传入的数据没有,则删除
$deletePermission = array_diff($permissions, $permissionsPost);
if($deletePermission) {
foreach($deletePermission as $key => $val) {
$authItem = AuthItem::find()->where(['name' => $val])->one();
if($authItem->is_permission == 0) {
AuthItemChild::deleteAll(['parent' => $model->name, 'child' => $val]);
}
}
}
// 默认给与权限
$allowPermission = ['/dashboard/*', '/uploader/*'];
foreach($allowPermission as $key => $val) {
$authItemChild = AuthItemChild::find()->where(['parent' => $model->name, 'child' => $val])->one();
if(empty($authItemChild)) {
$authItemChildModel = new AuthItemChild();
$authItemChildModel->parent = $model->name;
$authItemChildModel->child = $val;
$authItemChildModel->save();
}
}
return $this->redirect(['view', 'id' => $id]);
}
}
// 获取所有权限
// is_permission 0:表示参与权限管理,1:表示默认给与权限,比如一些Ajax,4:表示只有超级管理员才有的权限
$authItems = AuthItem::find()->where(['type' => 2, 'is_permission' => 0])->orderBy('index DESC')->all();
$list = $this->treelist($authItems);
return $this->render('view', [
'model' => $model,
'list' => $list,
'permissions' => $permissions
]);
}
/**
* Creates a new AuthItem model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return mixed
*/
public function actionCreate()
{
$model = new AuthItem();
if ($model->load(Yii::$app->request->post())) {
$model->type = 1;
if($model->save()) {
return $this->redirect(['index']);
}
}
return $this->render('create', [
'model' => $model,
]);
}
/**
* Updates an existing Permission model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['index']);
}
return $this->render('update', [
'model' => $model,
]);
}
/**
* Deletes an existing AuthItem model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* @param integer $id
* @return mixed
* @throws NotFoundHttpException if the model cannot be found
*/
public function actionDelete($id)
{
$model = $this->findModel($id);
$model->delete();
return $this->redirect(['index']);
}
/**
* Finds the AuthItem model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* @param integer $id
* @return AuthItem the loaded model
* @throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id)
{
if (($model = AuthItem::findOne($id)) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
private function makeInfo($items) {
// 修正auth_parent、 index、rule_name
foreach($items as $key => $val) {
if(empty($val->title)) {
$route = $val->name;
// 路由格式: /permission/index
// 路由格式: /permission/index
$route2 = str_replace('-', '_', $route);
$routeArr = explode('/', $route2);
if(count($routeArr) > 1) {
$action = $routeArr[2];
$controllerName = Yii::t('backend', $routeArr[1]);
$parent = '';
$title = '';
if(isset($routeArr[3])) {
$controllerName = Yii::t('backend', $routeArr[1]) . Yii::t('backend', $routeArr[2]);
$actionName = Yii::t('backend', 'action_' . $routeArr[3]);
$parent = $routeArr[1] . '_' . $routeArr[2];
$title = $actionName;
if($routeArr[3] == '*') {
$actionName = '';
$title = $controllerName;
}
} else {
$actionName = Yii::t('backend', 'action_' . $routeArr[2]);
$parent = $routeArr[1];
$title = $actionName;
if($routeArr[2] == '*') {
$actionName = '';
$parent = '';
$title = $controllerName;
}
}
// 只有超级管理员才能操作的
$adminPermission = ['admin', 'manager', 'rule-permission', 'gii', 'debug', 'test'];
// 默认给与权限的
$allowPermission = ['dashboard', 'uploader'];
// is_permission 0:表示参与权限管理,1:表示默认给与权限,比如一些Ajax,4:表示只有超级管理员才有的权限
$isPermission = 0;
foreach($adminPermission as $ak => $av) {
$adminIndex = stripos($route, $av);
if($adminIndex !== false) {
$isPermission = 4;
}
}
foreach($allowPermission as $ak => $av) {
$adminIndex = stripos($route, $av);
if($adminIndex !== false) {
$isPermission = 1;
}
}
$val->title = $title;
$val->index = 1;
$val->is_permission = $isPermission;
$val->auth_parent = $parent;
$val->save();
}
}
}
}
/**
* 权限二级管理
*/
private function treelist($items, $parent = '') {
$list = [];
foreach($items as $key => $val) {
if(empty($val->auth_parent)) {
$data['name'] = $val->name;
$data['title'] = $val->title;
$data['index'] = $val->index;
$data['auth_parent'] = $val->auth_parent;
$data['children'] = [];
$route2 = str_replace('-', '_', $val->name);
$routeArr = explode('/', $route2);
if(count($routeArr) > 1) {
$parent = '';
if(isset($routeArr[3])) {
$parent = $routeArr[1] . '_' . $routeArr[2];
} else {
$parent = $routeArr[1];
}
if(!empty($parent)) {
foreach($items as $k => $v) {
if($v->auth_parent == $parent) {
$sdata['name'] = $v->name;
$sdata['title'] = $v->title;
$sdata['index'] = $v->index;
$sdata['auth_parent'] = $v->auth_parent;
$data['children'][] = $sdata;
}
}
}
}
$list[] = $data;
}
}
return $list;
}
}
最终页面
接下来就是用户与角色,在Manager中新增角色选择
/**
* 获取到所有角色
*/
private function getAuthItems() {
return AuthItem::find()->where(['type' => 1])->all();
}
/**
* 获取当前角色
*/
private function getAuthAssignment($id) {
$authAssignment = AuthAssignment::find()->where(['user_id' => $id])->one();
return empty($authAssignment) ? '' : $authAssignment->item_name;
}
/**
* 保存角色
*/
private function maekAuthAssignment($id, $name) {
$authAssignment = AuthAssignment::find()->where(['user_id' => $id])->one();
if(empty($authAssignment)) {
$authAssignment = new AuthAssignment();
$authAssignment->item_name = $name;
$authAssignment->user_id = strval($id);//因为数据库是存的varchar,所以需要转
$authAssignment->save();
} else {
$authAssignment->item_name = $name;
$authAssignment->save();
}
}
<div class="form-group">
<div class="row row-box">
<div class="col-xs-2 col-sm-2 text-right">
<label class="control-label" for="course-name"><?= Yii::t('backend', 'rule_permission') ?></label>
</div>
<div class="col-xs-8 col-sm-8">
<?= Html::dropDownList('permission', $authAssignment, ArrayHelper::map($authItems, 'name', 'name'), ['class' => 'form-control', 'prompt' => Yii::t('backend', 'please_select')]) ?>
</div>
</div>
</div>