etm / etm_permisos
etm系统中的权限和角色
README
这是一个帮助我们以简单方式管理laravel中角色和权限的包。
创建自己的包
为了正确运行此包,Laravel中的Laravel/ui包必须已安装。
安装
在终端中运行以下命令
composer require etm/etm_permisos
包的使用
一旦在laravel中安装了包,建议使用以下命令来导出迁移、种子文件、视图、策略等
php artisan vendor:publish --provider="etm\etm_permisos\etmPermisosServiceProvider"
执行上述命令后,我们将检查laravel安装中的以下文件 config/etm_permisos.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 etm\etm_permisos\Traits\UserTrait; class User extends Authenticatable { //usamos el trait use UserTrait; // ... }
我们必须检查包在laravel安装中导出的种子文件etmPermissionInfoSeeder.php,其路径如下:database/seeds/ETMPermissionInfoSeeder.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(ETMPermissionInfoSeeder::class); } }
现在,我们可以在终端中执行以下命令
php artisan migrate --seed
一旦将所有表格及其权限加载到数据库中,你就可以通过/role访问角色,通过/user访问用户。
使用Gates和策略屏蔽控制器
Gates
假设我们有
- ETMPermissionInfoSeeder文件中的角色权限
- 一个名为: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')); } ... }
策略
假设你想进行一个检查,以确保用户可以查看自己创建的记录。我们将通过这个包提供的具体示例来解释如何做。
- 在seed文件中:ETMPermissionInfoSeeder.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,如果它有权限,则会显示,如果没有权限则不会显示。
贡献
感谢上帝帮助我为社区创建了这个包。愿上帝祝福你们。