基于角色的 Laravel 权限

2022-08-31 00:34:22

我正在尝试在Laravel应用程序中执行基于角色的权限控制。我想检查某些用户可以执行哪些操作,但我无法弄清楚如何在我的模型中实现门和策略(权限描述位于数据库中,并且是与存储资源ID的表关联的布尔值)。

这是 im 使用的数据库模型:

Diagram

我想知道laravel门在我的情况下是否有用,以及我如何实现它,如果没有,如何制作一个基本的中间件,负责权限控制以保护路由(或控制器)。

在表资源中,我有一个标识资源的uuid,别名是资源的名称,并具有操作或资源上下文的点表示法值(例如。'mysystem.users.create', 'mysystem.roles.delete', 'mysystem.users.images.view')。策略表具有描述用户权限的布尔值“allow”字段。

提前致谢。


答案 1

这就是我使用策略在 Laravel 中实现基于角色的权限的方式。

用户可以具有多个角色。角色具有关联的权限。每个权限都允许对特定模型执行特定操作。

迁移

角色表

class CreateRolesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('roles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name')->unique();
            $table->string('label');
            $table->text('description');
            $table->timestamps();
        });
    }
// rest of migration file

权限表

class CreatePermissionsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('permissions', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name')->unique();
            $table->string('label');
            $table->text('description');
            $table->timestamps();
        });
    }
// rest of migration file

权限角色数据透视表

class CreatePermissionRolePivotTable  extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('permission_role', function (Blueprint $table) {
            $table->integer('permission_id')->unsigned()->index();
            $table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade');
            $table->integer('role_id')->unsigned()->index();
            $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
            $table->primary(['permission_id', 'role_id']);
        });
    }
// rest of migration file

角色用户数据透视表

class CreateRoleUserPivotTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('role_user', function (Blueprint $table) {
            $table->integer('role_id')->unsigned()->index();
            $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade');
            $table->integer('user_id')->unsigned()->index();
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->primary(['role_id', 'user_id']);
        });
    }
// rest of migration file

模型

用户

public function roles()
    {
        return $this->belongsToMany(Role::class);
    }

public function assignRole(Role $role)
    {
        return $this->roles()->save($role);
    }

public function hasRole($role)
    {
        if (is_string($role)) {
            return $this->roles->contains('name', $role);
        }
        return !! $role->intersect($this->roles)->count();
    }

角色

class Role extends Model
{
    protected $guarded = ['id'];
    protected $fillable = array('name', 'label', 'description');
    public function permissions()
    {
        return $this->belongsToMany(Permission::class);
    }
    public function givePermissionTo(Permission $permission)
    {
        return $this->permissions()->save($permission);
    }
    /**
     * Determine if the user may perform the given permission.
     *
     * @param  Permission $permission
     * @return boolean
     */
    public function hasPermission(Permission $permission, User $user)
    {
        return $this->hasRole($permission->roles);
    }
    /**
     * Determine if the role has the given permission.
     *
     * @param  mixed $permission
     * @return boolean
     */
    public function inRole($permission)
    {
        if (is_string($permission)) {
            return $this->permissions->contains('name', $permission);
        }
        return !! $permission->intersect($this->permissions)->count();
    }
}

许可

class Permission extends Model
{
    protected $guarded = ['id'];
    protected $fillable = array('name', 'label', 'description');
    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }
    /**
     * Determine if the permission belongs to the role.
     *
     * @param  mixed $role
     * @return boolean
     */
    public function inRole($role)
    {
        if (is_string($role)) {
            return $this->roles->contains('name', $role);
        }
        return !! $role->intersect($this->roles)->count();
    }
}

政策

每个模型都需要一个策略。下面是模型的示例策略。该策略为“查看、创建、更新、删除”四个操作定义了“规则”。item

class ItemPolicy
{
    use HandlesAuthorization;
    /**
     * Determine whether the user can view the item.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function view(User $user)
    {
        $permission = Permission::where('name', 'items-view')->first();
        return $user->hasRole($permission->roles);
    }
    /**
     * Determine whether the user can create items.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function create(User $user)
    {
        $permission = Permission::where('name', 'items-create')->first();
        return $user->hasRole($permission->roles);
    }
    /**
     * Determine whether the user can update the item.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function update(User $user)
    {
        $permission = Permission::where('name', 'items-update')->first();
        return $user->hasRole($permission->roles);
    }
    /**
     * Determine whether the user can delete the item.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function delete(User $user)
    {
        $permission = Permission::where('name', 'items-delete')->first();
        return $user->hasRole($permission->roles);
    }
}

在 中注册每个策略AuthServiceProvider.php

use App\Item;
use App\Policies\ItemPolicy;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        Item::class => ItemPolicy::class,
    ];
// rest of file

控制器

在每个控制器中,请参阅策略中的相应授权操作。

例如,在以下方法中:indexItemController

public function index()
{
    $this->authorize('view', Item::class);

    $items = Item::orderBy('name', 'asc')->get();

    return view('items', ['items' => $items]);
}

视图

在您的视图中,您可以检查用户是否具有特定角色:

@if (Auth::user()->hasRole('item-administrator'))
// do stuff
@endif

或者如果需要特定权限:

@can('create', App\User::class)
// do stuff
@endcan

答案 2

回答您的问题如何制作一个基本的中间件,负责权限控制以保护路由(或控制器)?

举个例子:
这是您的路由
的简单角色中间件 AdminRole

namespace App\Http\Middleware;
use Illuminate\Support\Facades\Auth;
use Closure;

class AdminRole
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if(Auth::user()->role->name!=="admin"){ //Check your users' role or permission, in my case only admin role for routes
            return redirect('/access-denied');
        }
        return $next($request);
    }
}

定义此中间件后,将内核更新为.php文件

protected $routeMiddleware = [
    ..............
    'admin' =>\App\Http\Middleware\AdminRole::class,
    ...................
];

要使用此路由中间件:
有不同的方法可以使用路由中间件,但下面是一个示例

Route::group(['middleware' => ['auth','admin']], function () {
    Route::get('/', 'AdminController@index')->name('admin');
});

注意:在 laravel 上有一些用于角色和权限的工具和库,但上面是创建基本路由中间件的示例。


推荐