laravel-permission 安装
1 composer require spatie/laravel-permission
可以直接参考官方文档。
配置 1、发布配置文件 1 2 # 这条命令会在 config 下增加一个 permission.php 的配置文件 php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
2、注册 Autoloaded Service Providers
1 2 3 4 5 6 7 return [ ... 'providers' => [ Spatie\Permission\PermissionServiceProvider ::class , ] ];
3、运行数据库迁移
这里的表结构都可以根据业务进行调整。 比如,我们和前端 antd vue pro 框架对接,需要返回用户的菜单和权限,那么在 permission 表中,就可以增加【是否菜单:is_menu】字段,来区分菜单权限和普通权限。
需要排序,就增加对应的排序字段;
需要图标icon,就增加对应储存icon的字段;
需要层级结构,就增加父级id的字段;
…
数据库初始化时创建权限 在 database/seeders/DatabaseSeeder.php
中的 run()
方法中,可以创建系统默认权限、角色和用户。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 use Spatie \Permission \Models \Role ;use Spatie \Permission \Models \Permission ;app ()['cache' ]->forget ('spatie.permission.cache' );$user = Permission ::create ([ 'name' => 'menu.user.manage' , 'is_menu' => '1' , 'show' => '1' , 'parent_id' => '0' , 'parent_ids' => ',0,' , 'icon' => 'user' , 'sort' => '100' , 'component' => 'user/UserList' , 'path' => '/user/list' ]); Permission ::create ([ 'name' => 'menu.user.manage^add' , 'parent_id' => $user ->id, 'parent_ids' => ',0,' .$user ->id.',' // ",0,{$user->id} ," 这种写法也可以,需要使用双引号 ]); Permission ::create ([ 'name' => 'menu.user.manage^list' , 'parent_id' => $user ->id, 'parent_ids' => ',0,' .$user ->id.',' ]); Permission ::create ([ 'name' => 'menu.user.manage^info' , 'parent_id' => $user ->id, 'parent_ids' => ',0,' .$user ->id.',' ]); Permission ::create ([ 'name' => 'menu.user.manage^edit' , 'parent_id' => $user ->id, 'parent_ids' => ',0,' .$user ->id.',' ]); Permission ::create ([ 'name' => 'menu.user.manage^delete' , 'parent_id' => $user ->id, 'parent_ids' => ',0,' .$user ->id.',' ]); $role = Role ::create ([ 'name' => 'super' , 'show_name' => 'superAdmin' , 'sort' => '1' , ]); $role ->givePermissionTo (Permission ::all ());$user = Users ::create ([ 'name' => 'admin' , 'display_name' => '系统管理员' , 'department_id' => $department ->id, 'password' => bcrypt (Constants ::DEFAULT_PASSWORD ), ]); $user ->assignRole ('super' );
资源路由使用 permission 中间件
此软件包附带 RoleMiddleware 和 PermissionMiddleware 中间件。 你可以将它们添加到你的 app/Http/Kernel.php 文件中。
1 2 3 4 5 6 protected $routeMiddleware = [ 'role' => \Spatie\Permission\Middlewares\RoleMiddleware ::class , 'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware ::class , 'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware ::class , ];
然后,你可以使用中间件规则保护你的路由:
1 2 3 4 5 6 7 8 9 10 11 Route ::group (['middleware' => ['role:super-admin' ]], function () { }); Route ::group (['middleware' => ['permission:publish articles' ]], function () { }); Route ::group (['middleware' => ['role:super-admin' ,'permission:publish articles' ]], function () { });
但是,当路由使用 apiResources 时,对不同路由需要进行权限控制,我们不能直接在 Route 中使用中间件,因为不同的请求方式,我们需要验证不同的权限。(post验证有无【新增】权限,put和patch验证有无【编辑】权限,……)
1 2 3 4 5 6 7 Route ::apiResources ([ 'roles' => \App\Http\Controllers\Api\v1\RoleController ::class , 'departments' => \App\Http\Controllers\Api\v1\DepartmentController ::class , 'users' => \App\Http\Controllers\Api\v1\UserController ::class , 'dictionaries' => \App\Http\Controllers\Api\v1\DictController ::class , ]);
在 Laravue框架 的文档中,找到如下处理办法:
1 2 3 4 5 Route ::apiResource ('categories' , 'CategoryController' )->middleware ('permission:manage category' );Route ::get ('categories' , 'CategoryController@index' )->name ('categories.index' )->middleware ('permission:view category|manage category' );
即 额外定义对应路由中间件。个人觉得这样虽然可以实现功能,但破坏了 route 的美感,相当于不使用 apiResources
,手动定义了一遍全部的资源路由。
最后,研究中间件的时候,终于找到了一种我可以接受的解决方案:在 controller 中定义中间件。
1 2 3 4 5 6 7 8 public function __construct ( ) { $this ->middleware ('permission:publish articles' , ['only' => [ 'update' // Could add bunch of more methods too ]]); }
与 jwt 一起使用 因为 jwt 的 用户模型使用的 User 继承 Authenticatable,使用 laravel-permission 的 HasRoles Traits 也无法正常工作。
1 2 3 4 5 class User extends Authenticatable implements JWTSubject { ... }
这里使用继承 Model 的 Users,可以正常使用 使用 laravel-permission 的 HasRoles Traits。
1 2 3 4 class Users extends Model { ... }
经过调试定位,决定重写 permission 中间件。在 \App\Http\Middleware\
下创建 Permission 中间件,继承 laravel-permission 的 PermissionMiddleware。
修改用户实例,并使用 hasPermissionTo 判断权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 namespace App \Http \Middleware ;use App \Models \Users ;use Spatie \Permission \Exceptions \UnauthorizedException ;use Closure ;use Spatie \Permission \Middlewares \PermissionMiddleware as Middleware ;class Permission extends Middleware { public function handle ($request , Closure $next , $permission , $guard = null ) { $authGuard = app ('auth' )->guard ($guard ); if ($authGuard ->guest ()) { throw UnauthorizedException ::notLoggedIn (); } $user = Users ::find ($authGuard ->user ()->id); $permissions = is_array ($permission ) ? $permission : explode ('|' , $permission ); foreach ($permissions as $permission ) { if ($user ->hasPermissionTo ($permission )) { return $next ($request ); } } throw UnauthorizedException ::forPermissions ($permissions ); } }
最后,app/Http/Kernel.php 文件中,重新添加新的 permission 中间件
1 2 3 4 5 6 7 8 protected $routeMiddleware = [ 'permission' => \App\Http\Middleware\Permission ::class , ];
软件版本:laravel 8.54 参考资料