jhonatanfdez/jhonatanpermisos

Laravel 7 的角色和权限管理系统

1.0.4 2020-08-27 13:10 UTC

This package is auto-updated.

Last update: 2024-09-28 11:10:02 UTC


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对控制器中的每个方法进行两种方式的操作:

  1. 第一种方式使用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'));
    }
    ...
}
  1. 第二种方式使用$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'));
    }
    ...
}

更多信息请观看此视频

政策

假设您想实现一个检查,以便用户可以查看自己创建的记录。我们将通过本包提供的具体示例来解释如何实现:

  1. 在种子文件 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',
]);
  1. 附上如何在用户控制器或任何我们理解的控制器中进行政策验证的示例。在我们的例子中,我们在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'));
    }
  1. 为了确保上述功能正常工作,我们需要在文件 app/Providers/AuthServiceProvider.php 中进行一些调整,在我们的案例中,我们将观察位于 src/AuthServiceProvider.php 的此文件。

在我们的模块示例中,我们希望实现一个针对User模型的策略,因此您将观察到我们正在使用 App\UserApp\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的文件中。

此包执行的操作是接收两个参数:一个用于当前登录的用户,另一个用于所需的权限。

  1. 让我们查看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,如果有访问权限,则显示,如果没有访问权限,则不显示。

贡献

感谢上帝帮助我为社区创建了这个包。愿上帝祝福你们。

许可协议

MIT