【问题标题】:Role based authentication for different roles of user针对用户不同角色的基于角色的身份验证
【发布时间】:2019-01-27 12:02:54
【问题描述】:

我正在使用 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');
    });

我定义的关系如下:

用户.php

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

角色.php

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

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

如何检查特定角色是否可以访问特定菜单?

提前致谢

【问题讨论】:

  • @Erubiel 我添加了菜单和 menu_role 架构。请检查
  • 我复制并修改了我以前的代码......它是相同的模式,但有一个权限表......也许有些 id 或表是错误的,但主要的一般想法是有效的。

标签: laravel laravel-5.5


【解决方案1】:

您知道政策是如何运作的吗? 在这种情况下,它应该对您有很大帮助。 例如:您可以创建一个 MenuPolicy 文件,在其中放置菜单的所有限制/授权逻辑 然后只需根据您的策略在菜单的刀片文件中使用 @can 指令

检查那里 https://laravel.com/docs/5.6/authorization#creating-policies

【讨论】:

    【解决方案2】:

    您可以在用户和角色中检查这一点...我会在用户模型中这样做

    这样的东西应该在用户模型中工作......对于角色,只需删除与用户相关的表。

    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;
    }
    

    【讨论】:

    • 通过查询是可能的,我想尝试使用关系的 laravel 方式。有可能吗?
    • 我根据您的需要编辑了帖子...认为这可能有效。
    • 我猜在这种情况下查询会更好,因为可以有多个菜单,所以查询不会循环遍历每个菜单,而是会给出快速响应。感谢您的帮助。
    【解决方案3】:

    假设您有一个像 $menuId 这样的变量,您可以简单地将 whereHas() 与经过身份验证的用户一起使用并检查关系是否存在:

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

    【讨论】:

      【解决方案4】:

      您必须创建另一个数据透视表,例如

      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);
      }
      

      【讨论】:

        猜你喜欢
        • 2016-01-03
        • 1970-01-01
        • 1970-01-01
        • 2021-11-22
        • 2019-10-10
        • 2013-05-29
        • 2017-08-03
        • 1970-01-01
        • 2016-03-07
        相关资源
        最近更新 更多