luisrolespermisos / luispermisos
Laravel 7 的角色和权限系统
Requires (Dev)
- orchestra/testbench: ^6.2
README
LuisPermisos 是一个 Laravel 库,提供了角色和权限以及使用 Gates 和 Policies 的实现。
要求
为了使此包正常工作,Laravel 应安装 Laravel/ui 包。
安装
在终端中执行以下命令
composer require luisrolespermisos/luispermisos
包的使用
一旦在 Laravel 7 中安装了此包,建议使用以下命令来导出迁移、种子文件、视图、策略等
php artisan vendor:publish --provider="LuisRolesPermisos\LuisPermisos\LuisPermisosServiceProvider"
执行上述命令后,我们将检查以下文件在 Laravel 安装中的配置:config/LuisPermisos.php
return [ 'RouteRole' => 'role', 'RouteUser' => 'user', 'IdRoleDefault' => 2 ];
在此,我们可以更改默认的 URL,用于访问角色和用户。另一方面,我们还可以更改在注册用户时分配的默认角色 ID。如果在更改配置文件后更改没有反映出来,那么应该在终端中执行以下命令
php artisan config:clear
在执行命令之前
php artisan migrate
我们建议在 User 模型中进行以下配置
use Illuminate\Foundation\Auth\User as Authenticatable; //agregamos este trait use LuisRolesPermisos\LuisPermisos\Traits\UserTrait; class User extends Authenticatable { //usamos el trait use UserTrait; // ... }
我们需要检查由包在 Laravel 安装中导出的种子文件 LuisPermissionInfoSeeder.php,位于以下路径:database/seeds/LuisPermissionInfoSeeder.php,因为在此文件中,你可以找到以下内容
- 创建具有电子邮件 admin@admin.com 的管理员用户。用户名为 admin,密码为:admin。
- 创建两个角色:管理员角色和认证用户角色。
- 创建管理员角色和用户 admin 的关系。
- 创建默认权限。
以下是一个示例,说明在上述文件中创建权限的方式
//permission role $permission = Permission::create([ 'name' => 'List role', 'slug' => 'role.index', 'description' => 'A user can list role', ]); $permission_all[] = $permission->id; $permission = Permission::create([ 'name' => 'Show role', 'slug' => 'role.show', 'description' => 'A user can see role', ]); $permission_all[] = $permission->id; $permission = Permission::create([ 'name' => 'Create role', 'slug' => 'role.create', 'description' => 'A user can create role', ]); $permission_all[] = $permission->id; $permission = Permission::create([ 'name' => 'Edit role', 'slug' => 'role.edit', 'description' => 'A user can edit role', ]); $permission_all[] = $permission->id; $permission = Permission::create([ 'name' => 'Destroy role', 'slug' => 'role.destroy', 'description' => 'A user can destroy role', ]); $permission_all[] = $permission->id;
我们建议在此文件的末尾创建你需要的附加权限,结构与前面的相同。
一旦你有了所有需要的权限,你必须修改 DatabaseSeeder.php 文件来加载种子。
附上一个示例,说明该文件应该如何
use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { //$this->call(UsersTableSeeder::class); $this->call(LuisPermissionInfoSeeder::class); } }
现在,我们可以在终端中执行以下命令
php artisan migrate --seed
一旦将所有表和权限加载到你的数据库中,你就可以通过 URL /role 访问角色和 URL /user 访问用户。
使用 Gates 和 Policies 保护控制器
Gates
假设我们有
- LuisPermissionInfoSeeder 文件中的角色权限
- 名为 Role 的模型
- 名为 RoleController 的控制器
- 位于 views/role/index.blade.php 的 Blade 文件
假设你想要验证用户是否具有以下权限
$permission = Permission::create([ 'name' => 'Create role', 'slug' => 'role.create', 'description' => 'A user can create role', ]);
要使用 Gates 保护(检查用户是否有权访问一个方法)控制器的每个方法,有两种方式
- 第一种方式使用 Gates
namespace App\Http\Controllers; use Illuminate\Http\Request; use App\LuisPermission\Models\Role; use App\LuisPermission\Models\Permission; //Añadimos el facades Gate use Illuminate\Support\Facades\Gate; class RoleController extends Controller { ... public function create() { //Con gate revisamos si el usuario actual tiene acceso al permiso que tiene el slug: role.create Gate::authorize('haveaccess','role.create'); $permissions = Permission::get(); return view('role.create', compact('permissions')); } ... }
- 第二种方式使用 $this
namespace App\Http\Controllers; use Illuminate\Http\Request; use App\LuisPermission\Models\Role; use App\LuisPermission\Models\Permission; class RoleController extends Controller { ... public function create() { //con $this revisamos si el usuario actual tiene acceso al permiso que tiene el slug: role.create $this->authorize('haveaccess','role.create'); $permissions = Permission::get(); return view('role.create', compact('permissions')); } ... }
策略
假设你想要进行一个检查,以便用户可以查看他们创建的记录。我们将通过这个包提供的具体示例来解释如何操作。
- 在种子文件中:LuisPermissionInfoSeeder.php,我们需要添加我们想要的权限,并且必须考虑相同的结构,但最重要的是权限的slug,因为我们将使用这个字段来验证用户是否可以执行系统中的某个操作,附上适用于此场景的权限。
$permission = Permission::create([ 'name' => 'Show own user', 'slug' => 'userown.show', 'description' => 'A user can see own user', ]); $permission_all[] = $permission->id; $permission = Permission::create([ 'name' => 'Edit own user', 'slug' => 'userown.edit', 'description' => 'A user can edit own user', ]);
-
附上一个示例,说明如何在用户控制器或我们理解的控制器中实现策略验证。在我们的案例中,在UserController中,我们将放置适用于前面部分权限的方法
// userown.edit = 编辑自己的用户。
// userown.show = 查看自己的用户
public function show(User $user) { /* Aquí estamos trabajando con las políticas y por ende, estamos realizando dos validaciones: 1, con el user.show (En este lo que logramos es que si tienen el acceso global user.show puede ver todos los usuarios incluyendo su propio usuario) y 2, userown.show (En el cual vamos a validar si no tiene el user.show, va a revisar si tiene como segundo permiso el userown.show y si lo tiene, el podrá ver su propio usuario, de lo contrario, le mostrará acceso denegado). */ $this->authorize('view', [$user, ['user.show','userown.show'] ]); $roles= Role::orderBy('name')->get(); //return $roles; return view('user.view', compact('roles', 'user')); } ... public function edit(User $user) { /* Aquí estamos trabajando con las políticas y por ende, estamos realizando dos validaciones: 1, con el user.edit (En este lo que logramos es que si tienen el acceso global user.edit puede editar todos los usuarios incluyendo su propio usuario) y 2, userown.edit (En el cual vamos a validar si no tiene el user.edit, va a revisar si tiene como segundo permiso el userown.edit y si lo tiene, el podrá editar su propio usuario, de lo contrario, le mostrará acceso denegado). */ $this->authorize('update', [$user, ['user.edit','userown.edit'] ]); $roles= Role::orderBy('name')->get(); //return $roles; return view('user.edit', compact('roles', 'user')); }
- 为了使上述功能正常工作,我们必须在文件 app/Providers/AuthServiceProvider.php 中做一些调整,在我们的案例中,我们将观察位于 src/AuthServiceProvider.php 的此文件。
在模块的示例中,我们希望实现一个策略到User模型,因此您会看到我们使用了 App\User 和 App\Policies\UserPolicy。
namespace LuisRolesPermisos\LuisPermisos; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Gate; use App\User; //debemos agregar el modelo que vamos a usar use App\Policies\UserPolicy; //debemos agregar una política class AuthServiceProvider extends ServiceProvider { /** * The policy mappings for the application. * * @var array */ protected $policies = [ /* Debemos decirle a laravel que la política: UserPolicy se va a aplicar al modelo User. */ User::class => UserPolicy::class, ]; /** * Register any authentication / authorization services. * * @return void */ public function boot() { /*Desde aquí*/ $this->registerPolicies(); Gate::define('haveaccess', function (User $user, $perm){ //dd($perm); return $user->havePermission($perm); //return $perm; }); /*Hasta aquí*/ } }
在上一个文件的boot方法中,是整个包的核心,因此,此代码必须仅存在于此文件中,而不是Laravel的文件中。
此包执行的操作是接收两个参数,一个用于当前登录的用户,另一个是需要使用的权限。
- 我们来检查UserPolicy文件
namespace App\Policies; use App\User; use Illuminate\Auth\Access\HandlesAuthorization; class UserPolicy { use HandlesAuthorization; ... public function update(User $usera, User $user, $perm=null) { if ($usera->havePermission($perm[0])){ return true; }else if ($usera->havePermission($perm[1])){ return $usera->id === $user->id; } else { return false; } } ... public function view(User $usera, User $user, $perm=null) { if ($usera->havePermission($perm[0])){ return true; }else if ($usera->havePermission($perm[1])){ return $usera->id === $user->id; } else { return false; } } }
在上一个文件中,我们将找到如何在此包中处理策略的正确方式,并且它执行以下操作
- 接收3个参数
- 当前登录的用户,
- 我们要传递的用户,我们想要验证其是否有权限访问
- 策略的1部分中的权限。
仔细观察以下代码
/*confirmamos si tiene el acceso global como por ejemplo user.edit y si lo tiene retorno true para que me permita el acceso */ if ($usera->havePermission($perm[0])){ return true; } /* de lo contrario, si tiene el acceso userown.edit, el cual es usuado para saber si el usuario puede editar su propio registro, entonces hacemos una validación para saber si el usuario que está logueado puede está accediendo a su propio registro. Si es igual el id del usuario entonces retornará true y lo dejará pasar, si no es igual retornará false. */ else if ($usera->havePermission($perm[1])){ return $usera->id === $user->id; } else { return false; }
在Blade文件中禁用。
假设我们有以下权限
$permission = Permission::create([ 'name' => 'Create role', 'slug' => 'role.create', 'description' => 'A user can create role', ]);
在Blade中,我们可以使用** @can** 和 @endcan 指令来实现这一点。附上使用示例
@can('haveaccess','role.create') <a href="{{route('role.create')}}" class="btn btn-primary float-right" >Create </a> @endcan
如我们所见,我们只需要写两个参数
- 我们始终必须使用:haveaccess 作为第一个参数。
- 我们想要验证的权限的slug,如果用户有权限,则显示,如果没有权限则不显示。
贡献
愿上帝保佑你们。