Lumen企业站内容管理实战 - 权限和菜单管理

权限

 权限是一个重要的模块,很多新手写好这个模块,从现在开始,我们做做权限,基于RBAC0的权限模型,如果对这个不了解,请转到RBAC,这篇文章基本把原理介绍清楚了。

RBAC一共使用了六张表,分别是

  • 用户表(admins)
  • 角色表(roles)
  • 权限表(permissions)
  • 用户-角色关系表(admin_roles)
  • 角色-权限关系表(role_permissions)
  • 菜单表(menus)

用户-角色关系表是多对多关系,因为一个用户可以拥有多个角色,比如我是技术总监,同时呢我还是产品经理,那我就有两个角色了,同样的,一个角色也可以被多个人拥有,比如产品经理角色,有些公司产品经理是很多的。

角色-权限关系表也是对多多关系,一个角色可以拥有多个权限,一个权限也可以对应多个角色。

用户-角色关系、角色-权限关系是多对多关系相对来说更加灵活,从程序设计角度看,要考虑到业务的变更,同时这个部分改起来比较麻烦,所以我选择多对多关系。

菜单和权限是一对多关系,

使用数据迁移生成表,我们命令行走起

php artisan make:migration create_admins_table
php artisan make:migration create_roles_table
php artisan make:migration create_permissions_table
php artisan make:migration create_admin_roles_table
php artisan make:migration create_role_permissions_table

五个命令,一个行一行的执行,我们从admins表开始

public function up()
    {
        Schema::create('admins', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('user_name',20)->comment('用户名');
            $table->string('password',100)->comment('密码');
            $table->string('email',30)->default('')->comment('电子邮箱');
            $table->boolean('state')->default(0)->comment('状态,0:未启用,1:已启用');
            $table->timestamps();
        });
    }

角色表

public function up()
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('role_name',20)->comment('角色名');
            $table->boolean('state')->default(0)->comment('状态,0:未启用,1:已启用');
            $table->timestamps();
        });
    }

权限表

public function up()
    {
        Schema::create('permissions', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedInteger('menu_id')->comment('菜单ID');
            $table->string('name',30)->comment('权限名称');
            $table->string('path',50)->comment('路由文件中定义的路径');
            $table->timestamps();
        });
    }

用户角色关系表

public function up()
    {
        Schema::create('admin_roles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedInteger('admin_id')->comment('管理员ID');
            $table->unsignedInteger('role_id')->comment('角色ID');
            $table->timestamps();
        });
    }

角色权限关系表

public function up()
    {
        Schema::create('role_permissions', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedInteger('role_id')->comment('角色ID');
            $table->unsignedInteger('permission_id')->comment('权限ID');
            $table->timestamps();
        });
    }

菜单表

public function up()
    {
        Schema::create('menus', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedInteger('parent_id')->default(0)->comment('父ID');
            $table->string('name',30)->comment('名称');
            $table->timestamps();
        });
    }

 执行以下命令,生成以上表

php artisan migrate

 六张表很快就生成了

然后我们把模型给建立起来。切换到/app/Models/目录,同样的六个模型文件,蓝色的文件名是新建的。

我们先在模型里写个列表方法list()。菜单最多三级,所以,我with了三个child。菜单是树形结构,是一对多关系,所以使用hasMany。

<?php
namespace App\Models;


use Illuminate\Database\Eloquent\Model;

class Menu extends Model
{

    public function child()
    {
        return $this->hasMany(Menu::class, 'parent_id', 'id');
    }

    public static function lists()
    {
        return Menu::with('child.child.child')->where('parent_id',0)->get();
    }
}

我们定以下顺序吧,顺序是菜单管理、权限管理、角色管理、用户管理。

分别在/app/Http/Controllers/Admin/目下建立MenuController.php文件和/resources/views/admin/目录下新建menu目录,并且新建list.blade.php文件。对list.blade.php文件来说,复制文章分类的列表就行,然后改改就可以了。

控制器文件

<?php

namespace App\Http\Controllers\Admin;


use App\Http\Controllers\Controller;
use App\Models\Menu;
use Illuminate\Http\Request;

class MenuController extends Controller
{
    public function lists(Request $request)
    {
        $data['menu'] = Menu::lists();
        return view('admin.menu.list', $data);
    }
}

视图列表文件

再新写一组菜单的路由

// 菜单
    $router->get('/menu/list', 'MenuController@lists'); // 菜单列表
    $router->addRoute(['GET', 'POST'],'/menu/add', 'MenuController@add'); // 添加菜单
    $router->addRoute(['GET', 'POST'],'/menu/addChild/{id:[1-9]+}', 'MenuController@addChild'); // 添加子菜单
    $router->addRoute(['GET', 'POST'],'/menu/edit/{id:[1-9]+}', 'MenuController@edit'); // 编辑菜单
    $router->post('/menu/del', 'MenuController@del'); // 删除菜单

 刷新页面看看效果

 添加菜单

在菜单模型中添加一个add()方法。

public static function add(array $data)
    {
        $menu = new Menu();
        !empty($data['parent_id']) && $menu->parent_id = (int)$data['parent_id'];
        $menu->name = $data['name'];
        return $menu->save();

    }

在菜单控制器中,添加add()方法

public function add(Request $request)
    {

        if ($request->post()) {

            // todo 对新增数据做验证

            Menu::add($request->input());
            return $this->response->responseJSON();
        }

        return view('admin.menu.add');
    }

在菜单视图目录下新增一个add.blade.php文件,复制其它模块的add.blade.php文件就行

菜单编辑

在菜单模型中,新增一个edit()方法

public static function edit(Menu $menu, $data)
    {
        !empty($data['parent_id']) && $menu->parent_id = (int)$data['parent_id'];
        $menu->name = $data['name'];
        return $menu->update();
    }

控制中新增一个编辑方法

public function edit(int $id, Request $request)
    {

        $category = Menu::where('id', $id)->first();
//        if(empty($category->id)){
//            //跳转到错误页面
//        }

        if ($request->post()) {
            // todo 数据验证
            Menu::edit($category, $request->input());
            return $this->response->responseJSON();
        }

        $data['menu'] = $category;
        return view('admin.menu.edit', $data);
    }

 在菜单视图目录下,新建一个eidt.blade.php文件。然后我们编辑看看

编辑好了,接下来做添加子菜单

模型中已经有了添加菜单的方法了,所以我们就不用再改模型了,在控制器中新增一个addChild方法

public function addChild(int $id, Request $request)
    {

        // 同时获取父级的信息
        $category = Menu::with('parent')->where('id', $id)->first();
//        if(empty($category->id)){
//            //跳转到错误页面
//        }

        // 判断不是不post方式提交数据
        if ($request->post()) {

            // todo 数据验证

            Menu::add($request->input());
            return $this->response->responseJSON();
        }

        $data['menu'] = $category;
        return view('admin.menu.addChild', $data);
    }

 在菜单视图目录下,新建一个addChild.blade.php文件。

 

 子菜单添加成功

最后是删除,删除要注意一个问题就是,因为权限和菜单有关联关系,所以,删除菜单的话,那么被删除菜单下的子菜单以及权限都要删除,如果权限被删除的话,角色权限关系表中的数据也要删除,这样才能保持数据的一致性。

在菜单模型中,新写一个del方法

public static function del(array $ids)
    {
        return Menu::whereIn('id', $ids)->delete();
    }

 在菜单控制中,也新写一个del方法

public function del(Request $request)
    {
        $delRet = Menu::del($request->input('ids'));
        if (!$delRet) {
            $this->response->setMsg(500, '删除失败');
            return $this->response->responseJSON();
        }

        return $this->response->responseJSON();

    }

这个没有页面,是一个ajax请求,所以不需要视图。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangpeng52758

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值