jhonatanfdez / jhonatanpermisos
Laravel 7 的角色和权限管理系统
Requires (Dev)
- orchestra/testbench: ^5.3
README
这是一个帮助我们以简单方式管理 Laravel 7 中角色和权限的包。
创建自己的这个包
YouTube 上免费提供
如果您想了解我们如何一步一步地创建这个包中使用的结构,建议您访问以下 YouTube 链接 这里
仅在 Udemy 上提供
如果您已经有了角色和权限创建的基础,并想创建一个自定义包,该包可以通过以下命令安装到 Laravel 7 中
composer require jhonatanfdez/jhonatanpermisos
我们建议您在 Udemy 上购买课程,我们将免费在 YouTube 上做的项目转化为一个包。
如果您想了解如何做,请访问 这里
要求
Laravel/ui 包必须安装到 Laravel 中才能使此包正常运行。
安装
在终端中运行以下命令
composer require jhonatanfdez/jhonatanpermisos
包的使用
一旦将包安装到 Laravel 7 中,建议使用以下命令导出迁移、文件生成器、视图、策略等
php artisan vendor:publish --provider="Jhonatanfdez\JhonatanPermisos\JhonatanPermisosServiceProvider"
执行上述命令后,我们将检查 Laravel 安装中的以下文件 config/JhonatanPermisos.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 Jhonatanfdez\JhonatanPermisos\Traits\UserTrait; class User extends Authenticatable { //usamos el trait use UserTrait; // ... }
我们必须检查包安装到 Laravel 中的数据库种子文件 JhonatanPermissionInfoSeeder.php,其路径如下:database/seeds/JhonatanPermissionInfoSeeder.php,因为在这里你会找到以下内容
- 创建用户 admin,邮箱 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(JhonatanPermissionInfoSeeder::class); } }
现在我们可以在终端中执行以下命令
php artisan migrate --seed
一旦将所有表和权限加载到您的数据库中,您就可以通过 URL /role 访问角色,通过 URL /user 访问用户。
使用 Gates 和策略保护控制器
Gates
假设我们有
- JhonatanPermissionInfoSeeder 文件中的角色权限
- 名为: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\JhonatanPermission\Models\Role; use App\JhonatanPermission\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\JhonatanPermission\Models\Role; use App\JhonatanPermission\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')); } ... }
政策
假设您想实现一个检查,以便用户可以查看自己创建的记录。我们将通过本包提供的具体示例来解释如何实现:
- 在种子文件 JhonatanPermissionInfoSeeder.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中设置前面部分中放置的权限方法
- useroun.edit = 编辑自己的用户
- useroun.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 Jhonatanfdez\JhonatanPermisos; 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,如果有访问权限,则显示,如果没有访问权限,则不显示。
贡献
感谢上帝帮助我为社区创建了这个包。愿上帝祝福你们。