Я использую laravel 5.5, где я разрабатываю Аутентификацию на основе ролей для пользователей. Пользователь системы может иметь несколько ролей, и эти роли могут иметь доступ к нескольким меню. Я хочу проверить, есть ли у текущих ролей пользователя доступ к определенному меню.

Ниже приведена структура моей таблицы

Schema::create('users', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->string('email')->unique();
        $table->string('password');
        $table->rememberToken();
        $table->timestamps();
        $table->dateTime('deleted_at')->nullable(); 
    });

     Schema::create('roles', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name')->unique();
        $table->longText('description')->nullable();
        $table->timestamps();
        $table->dateTime('deleted_at')->nullable(); 
    });

      Schema::create('role_user', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('user_id');
        $table->integer('role_id');
        $table->integer('is_default')->default(0);
        $table->timestamps();
        $table->dateTime('deleted_at')->nullable(); 

        $table->foreign('user_id')
                ->references('id')->on('users')
                ->onDelete('cascade');

        $table->foreign('role_id')
                ->references('id')->on('roles')
                ->onDelete('cascade');
    });

    Schema::create('menus', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('parent_id');
        $table->string('name')->unique();
        $table->string('action')->unique();
        $table->integer('sequence');
        $table->timestamps();
        $table->dateTime('deleted_at')->nullable(); 
    });

    Schema::create('menu_roles', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('menu_id');
        $table->integer('role_id');
        $table->timestamps();
        $table->dateTime('deleted_at')->nullable(); 


        $table->foreign('menu_id')
                ->references('id')->on('menus')
                ->onDelete('cascade');

        $table->foreign('role_id')
                ->references('id')->on('roles')
                ->onDelete('cascade');
    });

Я определил отношения следующим образом:

User.php

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

Role.php

public function users()
{
    return $this->belongsToMany(User::class);
}

public function menus()
{
    return $this->belongsToMany(Menu::class);
}

Как я могу проверить, есть ли у определенной роли доступ к определенному меню?

Заранее спасибо

2
Akshay Deshmukh 21 Авг 2018 в 13:07

4 ответа

Лучший ответ

Вы можете проверить это в User и в Role ... я бы сделал это в User Model

Нечто подобное должно работать в пользовательской модели ... для роли, просто удалите пользовательские таблицы.

public function checkMenuPermission($key)
{

    // YOUR KEY can be name, id, any unique column... 

    $results = DB::table('users')
                    ->join('role_user', 'users.id', '=', 'role_user.user_id')
                    ->join('menu_roles', 'role_user.role_id', '=', 'menu_roles.role_id')
                    ->join('menus', 'menus.id', '=', 'menu_roles.menu_id')
                    ->select('menus.name')
                    ->where('users.id', $this->id)
                    ->where('menus.name', $key)
                    ->orderBy('menus.name')
                    ->distinct()
                    ->get()->count();

    return $results > 0 ? true : false;
}

Тогда в ваших контроллерах просто можно назвать это как $user->checkMenuPermission('someSome');

Изменить

Если вы хотите сделать это только с Eloquent , вы можете

public function checkMenuPermission($key){
    foreach($this->menus as $m){
      if($m->name == $key){
         return true;
      }
    }
    return false;
}
1
Erubiel 22 Авг 2018 в 05:30

Предполагая, что у вас есть переменная типа $menuId, вы можете просто использовать whereHas () с аутентифицированным пользователем и проверьте, существуют ли отношения:

$canAccess = auth()->user()->whereHas('roles.menus', function ($query) use($menuId) {

    $query->where('id', $menuId);

})->exists();
0
Rwd 21 Авг 2018 в 10:24

Вы знаете, как работают политики? Это должно вам очень помочь в этом случае. Е.Г .: Вы можете создать файл MenuPolicy, в который вы поместите всю логику ограничений / авторизаций для меню. А затем просто используйте директиву @can в блейд-файле меню в соответствии с вашими правилами

Проверьте там https://laravel.com/docs/5.6/authorization#creating-policies

0
r0ulito 23 Авг 2018 в 06:31

Вы должны создать еще одну сводную таблицу, что-то вроде

Schema::create('role_menu', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('menu_id');
    $table->integer('role_id');

    $table->foreign('menu_id')
            ->references('id')->on('menus')
            ->onDelete('cascade');

    $table->foreign('role_id')
            ->references('id')->on('roles')
            ->onDelete('cascade');
});

Очевидно, должна быть таблица menus.

Чем больше возможностей открывается ... Я думаю, что лучший способ - создать промежуточное ПО, которое можно использовать для маршрутов конкретного меню.

Например:

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    // Check user roles in order to check if role has access to the menu
    foreach($request->user()->roles as $role) {
        // This code supposes that your route is something like http://app.tld/menus/{menu_id}
        if($role->menus()->find($request->route('menu_id'))) {
            return $next($request);
        }
    }

    // Otherwise abort, redirect.. whatever
    abort(401);
}
-1
IlGala 21 Авг 2018 в 10:24
51946307