Laravel系列之CMS系统学习 — 角色、权限配置【2】
一、rbac分析
基于角色的权限访问控制(role-based access control),这里存在这么几个玩意儿:角色、权限,用户
表:roles、permissions、role_has_permissions、model_has_roles、model_has_permissions(最后两张表可以看4.1有解释)
明确:用户属于什么角色,那么角色拥有什么权限,用户自然拥有
然后配置,就(后面就不添加了)~
二、角色的增删改查
这个就很普通的功能了,略???
但是有一些需要注意的地方:
1. 更新操作时,method使用put
2. laravel的唯一性验证举例:'title' => 'required|unique:roles,title,'.$id,
解释:对title字段进行验证——必填|唯一性验证:从拿一张表进行验证,验证什么字段,不验证当前字段(意思就是:比如你要修改的信息叫张三,表里面只有你当前编辑的这条记录是张三,所以忽略要这条记录,不然不就不唯一了嘛~)
3.laravel再进行更新、删除操作时,需要进行传参(也就是你要删除那一条记录的唯一标识),而要想获取这个参数可以使用:$this->route('xxx')
三、权限(很重要,自学的过程中卡了好久)
控制权限的方式有很多种,但我个人认为,(也是组长要求哈哈哈哈)最合适的方式是中间件
1. 路由定义
1 // 权限管理 2 route::get('role/permission/{role}', 'rolecontroller@permission');//页面显示 3 route::post('role/permission/{role}', 'rolecontroller@permissionstore');//提交表单
2. 页面展示
无论通过modals还是页面来显示权限页面都可以,我觉得少的话使用modals(注意使用modals的话,就不用show方法了),多的话页面展示
然后就是遍历权限,有两种方法
方法一:遍历permission.php文件
方法二:通过方法来获取
1 public function permission(role $role) 2 { 3 // 根据guard来获取权限 4 $modules = \hdmodule::getpermissionbyguard('admin'); 5 6 // 分配 7 // 之所以分配role是因为1.要进行checkbox选中判断,也就是判断当前用户是否有某权限 2.提交表单role_id 8 return view('admin::role.permission', compact('role'), compact('modules')); 9 }
然后就可以进行页面渲染了,@foreach就好啦~ 里面的一大堆input只是样式啦~
1 @extends('admin::layouts.master') 2 @section('content') 3 @component('components.tabs',['title'=>$role->title.'权限设置']) 4 @slot('nav') 5 <li class="nav-item"><a href="/admin/role" class="nav-link">角色列表</a></li> 6 <li class="nav-item"><a href="#" class="nav-link active">权限设置</a></li> 7 @endslot 8 @slot('body') 9 <form action="/admin/role/permission/{{$role['id']}}" method="post"> 10 @csrf 11 @foreach($modules as $module) 12 <div class="card-body pb-0"> 13 @foreach($module['rules'] as $rule) 14 <div class="card card-flat"> 15 <div class="card-header">{{$rule['group']}}</div> 16 <div class="col-12 col-sm-8 col-lg-6 form-check mt-2"> 17 @foreach($rule['permissions'] as $k=>$permission) 18 <p hidden>{{$i = $k + rand(0,1000000)}}</p> 19 <div class="checkboxwrapper theme3 extrasmallcheckboxsize mr-3" 20 style="float: left;"> 21 <input type="checkbox" name="name[]" id="sample{{$i}}" 22 {{$role->haspermissionto($permission['name'])?'checked=""':''}} value="{{$permission['name']}}"> 23 <label for="sample{{$i}}"> 24 <i> 25 <svg version="1.1" id="layer_1" xmlns="http://www.w3.org/2000/svg" 26 xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 27 width="50px" height="50px" viewbox="0 0 50 50" 28 enable-background="new 0 0 50 50" xml:space="preserve"> 29 <circle fill="none" stroke="#b7b7b7" stroke-width="3" stroke-miterlimit="10" cx="25.11" cy="24.883" 30 r="23.519"/> 31 <path fill="none" stroke-width="3" stroke-miterlimit="10" d="m48.659,25c0,12.998-10.537,23.534-23.534,23.534 32 s1.591,37.998,1.591,25s12.127,1.466,25.125,1.466c9.291,0,17.325,5.384,21.151,13.203l19,36l-9-14"/> 33 </svg> 34 </i> 35 <span style="float: right;margin-top: 3px;font-size: 14px;margin-left: 5px">{{$permission['title']}}</span> 36 </label> 37 </div> 38 @endforeach 39 </div> 40 </div> 41 @endforeach 42 </div> 43 @endforeach 44 <button class="btn btn-primary">保存</button> 45 </form> 46 @endslot 47 @endcomponent 48 @endsection
3. 给用户设置权限
1 public function permissionstore(request $request, role $role) 2 { 3 $role->syncpermissions($request->name); // 同步权限 4 session()->flash('success', '修改权限成功'); 5 6 return back(); 7 }
4. 根据用户来控制后台侧边导航栏的显示
4.1 初始化管理员角色
4.1.1 分配角色 —— 角色属于那个模型
解释:因为cms系统是多模块的,那么角色就得和不同模块绑定关系,不绑定就不可能操作该模块
$user->assignrole(['super_user', 'admin']);
注意:laravel默认是没有这方法的,所以需要拓展模型(模拟多继承)
1 <?php 2 3 namespace app; 4 5 use illuminate\notifications\notifiable; 6 use illuminate\foundation\auth\user as authenticatable; 7 use spatie\permission\traits\hasroles; 8 9 class admin extends authenticatable 10 { 11 use notifiable; 12 use hasroles; 13 }
4.2 侧边导航栏显示
目的:给用户分配了什么权限,侧边导航栏就显示相应的权限链接
实现:
1. 再config文件当中,将menus.php 和 permission.php 的 permission配置项进行统一
2. 修改_menus.blade.php文件
1 <div class="left-sidebar-scroll"> 2 <div class="left-sidebar-content"> 3 <ul class="sidebar-elements"> 4 @foreach(\hdmodule::getmenus() as $modulename => $groups) 5 @foreach($groups as $group) 6 <li class="divider">{{$group['title']}}</li> 7 <li class="parent open"> 8 <a href="#"><i class="{{$group['icon']}}"></i> <span>{{$group['title']}}</span></a> 9 <ul class="sub-menu"> 10 @foreach($group['menus'] as $menu) 11 @can($menu['permission']) 12 <li> 13 <a href="{{$menu['url']}}" pjax><i 14 class="{{$menu['icon']}}"></i><span> {{$menu['title']}}</span></a> 15 </li> 16 @endcan 17 @endforeach 18 </ul> 19 </li> 20 @endforeach 21 @endforeach 22 </ul> 23 </div> 24 </div>
解释:@can是laravel的指令,用来检查用户是否具有某种权限
5. 站长权限(超级管理员权限)
5.1 对laravel-permission的致敬
我使用的laravel-module中是有对laravel-permission的一个改良,比如对中间件验证权限的改良(larave-permission处理不够灵活并对资源控制器支持不好)
laravel-module:
1. 在进行store和update的权限验证时,会自动对跳转到create、edit进行验证
2. 在进行站长权限判断时,一步即可(而laravel-permission需要先进行用户属于什么角色判断,再进行有什么权限判断两步)
5.2 修改config/menus.php和config/permission.php文件
之前在这两个文件中,对permission配置项进行了语义化的书(比如admin模块下的角色管理中的permission配置项写的是admin::config-roles),但其实这2个文件并不对用户开放,且一旦系统成型修改不大,所以运用了以下写法
1 <?php return [ 2 0 => 3 [ 4 'title' => '系统管理', 5 'icon' => 'fa fa-navicon', 6 'permission' => ['modules\admin\http\controllers\rolecontroller@index'], 7 'menus' => 8 [ 9 [ 10 'title' => '角色管理', 11 'icon' => 'fa fa-user-md', 12 'permission' => 'modules\admin\http\controllers\rolecontroller@index', 13 'url' => '/admin/role', 14 ], 15 ], 16 ], 17 ];
1 <?php 2 /** 3 * 权限配置 4 * 为了避免其他模块有同名的权限,权限标识要以 '控制器@方法' 开始 5 */ 6 return [ 7 [ 8 'group' => '角色管理', 9 'permissions' => [ 10 [ 11 'title' => '角色列表', 12 'name' => 'modules\admin\http\controllers\rolecontroller@index', 13 'guard' => 'admin', 14 ], 15 [ 16 'title' => '添加角色', 17 'name' => 'modules\admin\http\controllers\rolecontroller@create', 18 'guard' => 'admin', 19 ], 20 [ 21 'title' => '删除角色', 22 'name' => 'modules\admin\http\controllers\rolecontroller@destory', 23 'guard' => 'admin', 24 ], 25 [ 26 'title' => '修改角色', 27 'name' => 'modules\admin\http\controllers\rolecontroller@edit', 28 'guard' => 'admin', 29 ], 30 [ 31 'title' => '修改角色权限', 32 'name' => 'modules\admin\http\controllers\rolecontroller@permission', 33 'guard' => 'admin', 34 ], 35 ], 36 ], 37 ];
修改之后,相应的_menus.blade.php也需要进行修改
1 <div class="left-sidebar-scroll"> 2 <div class="left-sidebar-content"> 3 <ul class="sidebar-elements"> 4 @foreach(\hdmodule::getmenus() as $modulename => $groups) 5 @foreach($groups as $group) 6 <li class="divider">{{$group['title']}}</li> 7 <li class="parent"> 8 @if(\hdmodule::hadpermission($group['permission'],'admin')) 9 <a href="#"><i class="{{$group['icon']}}"></i> <span>{{$group['title']}}</span></a> 10 <ul class="sub-menu"> 11 @foreach($group['menus'] as $menu) 12 @if(\hdmodule::hadpermission($menu['permission'],'admin')) 13 <li> 14 <a href="{{$menu['url']}}" pjax><i 15 class="{{$menu['icon']}}"></i><span> {{$menu['title']}}</span></a> 16 </li> 17 @endif 18 @endforeach 19 </ul> 20 </li> 21 @endif 22 @endforeach 23 @endforeach 24 </ul> 25 </div> 26 </div>
5.3 站长权限配置
整个站都是属于他/她的,所以不需要对其进行验证
5.3.1 确定站长
运行 php artisan vender:publish --provider="houdunwang\module\laravelserviceprovider"
在config/hd_module中就会有webmaster配置项啦
5.3.2 忽略检测站长权限
只需要将用户标识和webmaster配置项对应即可
5.3.3 添加中间件
在进行后台的任何操作时候,就需要进行中间件来判断是否该用户是站长
此时就需要路由
1 <?php 2 3 route::group( 4 ['middleware' => 'web', 'prefix' => 'admin', 'namespace' => 'modules\admin\http\controllers'], 5 function () { 6 auth::routes(); 7 } 8 ); 9 10 route::group( 11 ['middleware' => ['web', 'auth:admin'], 'prefix' => 'admin', 'namespace' => 'modules\admin\http\controllers'], 12 function () { 13 // 后台首页 14 route::get('/', 'admincontroller@index'); 15 16 // 角色管理 17 route::resource('role', 'rolecontroller')->middleware('permission:superadmin'); 18 19 // 权限管理 20 route::get('role/permission/{role}', 'rolecontroller@permission')->middleware('permission:superadmin'); 21 route::post('role/permission/{role}', 'rolecontroller@permissionstore')->middleware('permission:superadmin'); 22 } 23 );
注意:
1. 这个中间件是路由中间件,所以需要到app/http/kernel.php中进行注册(之后所以自定义的中间件都是如此,只是需要注册在相应位置即可)
2. middleware('permission:admin');中的admin参数是守卫者不是webmaster配置项
3.middleware('permission:admin,resource');中的resource参数时针对resource路由才添加
'permission' => \houdunwang\module\middlewares\permissionmiddleware::class,
6. 零碎
6.1 修复vue模板中不能使用js的情况
需要使用@yield("")占位符,不然会报vue模板错误
6.2 模型删除操作和表外键约束注意事项
站长可不敢删除啊
依赖表数据变化,本表数据删除