使用laravel+Laravel-Roles-Permissions开发后台权限管理
最终效果如下图: 起源
今年以前本人开发PHP一直都是使用的ThinkPHP、codeigniter和微擎作为主要框架。自从去年偶然间听说Laravel这个框架就被他吸引住了,但是一直没有机会进行全面性的学习。直到今年年初接了一个很简单的项目,想到laravel开发效率高所以才开始制定学习计划由于时间比较紧所以就现炒现卖,然而在开始码代码的时候我就遇到一个难题,我需要搭建一个通用的后台,为了以后能更好的复用嘛。然而这个不是最坑,最坑的是Laravel没有完整的权限解决方案(可能是我找轮子的能力还不够吧),直到找到一位大佬使用(laravel+Laravel-Roles-Permissions)开发的脚手架《Associate users with roles and permissions》(https://github.com/spatie/laravel-permission)感觉和我的需求很接近于是就拿来研究研究看看有没有改造空间。上面是截图,这个脚手架还应用了一些Laravel的新组件这里就不一一介绍了。
改造过程
轮子找到了,但是不适合我的需要。我想要的是权限能够分类,按照不同分类进行权限分配。于是下面就是对轮子进行一系列的操作了,比如说加个胎压检测器什么的好兼容自己的小奔奔嘛(网上针对这个权限系统的说明还是挺多的毕竟是最人性化的权限管理了嘛)。
拿到源码跑起来发现与我的需求相差不多,无非就是权限多关联一个权限分类表。还有一个问题就是由于权限名称和角色名称全是英文感觉很适合我们大天朝。于是就想到再关联一个权限别名表和一个角色别名表。最开始我想到的是能不能修改底层模块的源码,但是我又不想破坏composer相关组件,否则我git到其他地方就跑步了了还必须把改过的组件拷过去,破坏别人的劳动成果这不符合我的作风。想了半天突然灵光一闪OOP不是可以继承的嘛?笨。
(话说底层好像有一个 model_has_permissions 和 model_has_roles表但是发现得比较晚就没有折腾而是自己动手撸了一个)
于是说干就干,下面是改造的具体过程:
一、数据库改造
二、Permission改造 在Models里建了一个叫Permission_ 的model使用它继承于Spatie\Permission\Models\Permission 然后关联上别名表和分类表具体代码如下
<?php
namespace App\Http\Models\Admin;
use Spatie\Permission\Models\Permission;
class Permission_ extends Permission
{
//
// protected $table="permission";
public function classify_belongsToMany()
{
//关联分类表
return $this->belongsToMany('App\Http\Models\Admin\ClassifyPermissions','classify_has_permissions','permission_id','classify_id');
}
public function hasDetails()
{
//关联别名表
return $this->hasOne('App\Http\Models\Admin\PermissionsDetails','permission_id');
}
}
1.列表页(具体效果如下图):
1)在PermissionsController里面调用 相关权限和别名
public function index()
{
if (! Gate::allows('watch power')) {
return abort(401);
}
$permission= new Permission_();
$permissions = $permission->with(['hasDetails','classify_belongsToMany'])->get();
return view('admin.manage.permissions.index', compact('permissions'));
}
2)在Permissions/index.blade.php文件 相关权限和别名
<!--显示别名(explain为数据库中别名的名称)-->
@if(!empty($permission->hasDetails))
{{$permission->hasDetails->explain}}
@endif
<!--显示所属分类-->
@if(!empty(count($permission->classify_belongsToMany)))
<label class="label label-info">{{ $permission->classify_belongsToMany[0]->title }}</label>
@endif
2.add页面【update修改页面同理】(效果如下图):
1)在PermissionsController里面调用 相关权限和别名
public function create()
{
if (!Gate::allows('create power')) {
return abort(401);
}
//获取所分类
$classify = ClassifyPermissions::where(array('parent_id' => 0))->orderBy('rank', 'DESC')->with(['classifyHasMany'])->get();
return view('admin.manage.permissions.create', compact('classify'));
}
public function store(StorePermissionsRequest $request)
{
if (!Gate::allows('create power')) {
return abort(401);
}
$this->validator($request->all())->validate();
$per_arr = $request->all();
$classify_ids = $per_arr['classify'];
unset($per_arr['classify'], $per_arr['explain']);
$permission = Permission_::where(array('name' => $per_arr['name']))->get();
//如果此权限已经存在
if (!empty(count($permission))) {
return back()->with('alert_message', ['type' => 'error', 'message' => '此权限名已存在!']);
}
$inser_per = Permission_::create($per_arr);
$inser_per->classify_belongsToMany()->sync($request->input('classify'));
//操作关联数据 (没有找到关联存储比较好的方法 这里使用笨方法 先存储在拿id进行关联)
$details = new PermissionsDetails;
$details->permission_id = $inser_per->id;
$permission = $details->where(array('permission_id' => $inser_per->id))->get();
$details->explain = $request->input('explain');
if (empty(count($permission))) {
$details->save();
} else {
$details->update();
}
return redirect()->route('admin.manage.permissions.index');
}
2)在Permissions/cree.blade.php文件 相关权限和别名
<!--权限别名-->
<div class="row">
<div class="col-xs-12 form-group">
{!! Form::label('explain', trans("global.manage.permissions.fields.explain").'*', ['class' => 'control-label']) !!}
<!-- {!! Form::text('explain', old('explain'), ['class' => 'form-control', 'placeholder' => '', 'required' => '']) !!} -->
@if(!empty($permission->hasDetails))
<input class="form-control" placeholder="" required="" name="explain" type="text" id="explain" value="{{$permission->hasDetails->explain}}">
@else
<input class="form-control" placeholder="" required="" name="explain" type="text" id="explain" value="">
@endif
<p class="help-block"></p>
@if($errors->has('explain'))
<p class="help-block">
{{ $errors->first('explain') }}
</p>
@endif
</div>
</div>
<!--权限选择 这里第一级不作为选择对象-->
<div class="row">
<div class="col-xs-12 form-group">
{!! Form::label('classify', trans("global.manage.permissions.fields.classify").'*', ['class' => 'control-label']) !!}
<!--
{!! Form::select('classify[]', $classify, old('classify') ? old('classify') : '', ['class' => 'form-control select2', 'multiple' => 'multiple']) !!}
-->
<select class="form-control select2" data-placeholder="请选择权限分类" style="width: 100%;" name="classify">
<option value="" >请选择权限分类</option>
@foreach($classify as $cl_k => $cla)
<optgroup label="{{$cla['title']}}">
@foreach($cla->classifyHasMany as $clss_k => $class)
@if(!empty(count($permission->classify_belongsToMany)) && $permission->classify_belongsToMany[0]->id==$class['id'])
<option value="{{$class['id']}}" selected >{{$class['title']}}</option>
@else
<option value="{{$class['id']}}">{{$class['title']}}</option>
@endif
@endforeach
</optgroup>
@endforeach
</select>
<p class="help-block"></p>
@if($errors->has('classify'))
<p class="help-block">
{{ $errors->first('classify') }}
</p>
@endif
</div>
</div>
三、roles 改造 (同Permission改造一样创建一 Roles_)
1.列表页(具体效果如下图):
1)在RolesController里面调用
public function index()
{
if (! Gate::allows('watch roles')) {
return abort(401);
}
$roles = Role_::all();
$Permissions=new Permission_();
//关联获取所有权限和别名
$Permissions = $Permissions->with(['hasDetails'=>function($query){
}])->get();
return view('admin.manage.roles.index', compact('roles','Permissions'));
}
2)在Roles/index.blade.php文件 修改
<td style="line-height:25px;">
@foreach ($role->permissions()->pluck('name') as $permission)
@if(!empty(count($Permissions)))
@foreach($Permissions as $per_k => $per)
@if($permission ==$per['name'])
@if(!empty($per->hasDetails))
<span class="label label-info label-many">{{$per->hasDetails['explain']}}</span>
@else
<span class="label label-info label-many"> {{$per['name']}}</span>
@endif
@else
<!-- <span class="label label-info label-many">{{ $permission }}</span> -->
@endif
@endforeach
@else
<span class="label label-info label-many">{{ $permission }}</span>
@endif
@endforeach
</td>
1.update修改页面(create页面同理):
1)在RolesController里面调用
public function create()
{
if (! Gate::allows('create roles')) {
return abort(401);
}
$permissions = Permission_::get()->pluck('name', 'name');
// $Permissions=new Permissions();
// $Permissions = $Permissions->with(['classifyHasMany'=>function($query){
// $query->with(['hasManyDetails'=>function($qu_det){
// $qu_det->with('hasDetails');
// }]);
// }])->get();
$classify_per=new ClassifyPermissions();
$classify = $classify_per->where(array('parent_id' => 0))->orderBy('rank', 'DESC')->with(['classifyHasMany'=>function($query){
$query->with(['hasManyDetails'=>function($qu_det){
$qu_det->with('hasDetails');
}]);
}])->get();
// dd($permissions);die;
return view('admin.manage.roles.create', compact('role','classify'));
}
public function store(StoreRolesRequest $request)
{
if (! Gate::allows('create roles')) {
return abort(401);
}
$role = Role_::create($request->except('permission'));
$permissions = $request->input('permission') ? $request->input('permission') : [];
$role->givePermissionTo($permissions);
return redirect()->route('admin.manage.roles.index');
}
2)在Roles/edit.blade.php文件 修改
<div class="row">
<div class="col-xs-12 form-group">
{!! Form::label('permission', _lang('fields.check_permission'), ['class' => 'control-label']) !!}
@foreach($classify as $cl_k => $cla)
<div class="">
<div class="col-xs-6 form-group">
<div class="box box-success">
<div class="classify-group">
<div class="box-header">
<h3 class="box-title">
<label>
<input type="checkbox" class="minimal">
{{$cla['title']}}
</label>
</h3>
</div>
@if(!empty(count($cla->classifyHasMany)))
@foreach($cla->classifyHasMany as $clss_k => $class)
<div class="box-body">
<div class="form-group">
<span class="classify">
<label>
<input type="checkbox" class="minimal">
{{$class['title']}}
</label>
</span>
<span class="permission">
@if(!empty(count($class->hasManyDetails)))
@foreach($class->hasManyDetails as $per_k => $per)
<label>
<input type="checkbox" class="minimal" name="permission[]" value="{{$per['name']}}" @if(!empty(count($permissions))) @foreach($permissions as $permission_k=> $permission)
@if($permission ==$per['name'])
checked='checked'
@endif
@endforeach
@endif
/>
@if(!empty($per->hasDetails))
{{$per->hasDetails['explain']}}
@else
{{$per['name']}}
@endif
</label>
@endforeach
@endif
</span>
</div>
</div>
@endforeach
@endif
</div>
</div>
</div>
</div>
@endforeach
</div>
</div>
(全选功能这里就不贴代码了select2的全选比较简单自己研究一下就能搞定)
源码地址:点击查看
以上均为原创经验,如有不足请在评论区指出。