具有多个角色的 Laravel 中间件

Posted

技术标签:

【中文标题】具有多个角色的 Laravel 中间件【英文标题】:Laravel middleware with multiple roles 【发布时间】:2017-10-09 15:32:55 【问题描述】:

我在使用 Laravel 的中间件时遇到了一些问题。 让我告诉你我想要完成的基本想法:

网站上的注册用户将拥有以下四种角色之一:

    学生(默认):可以访问“index”和“show”视图 审批人:可以访问以前的,加上'overview'、'update' 编辑器:可以访问以前的,加上'create'、'edit'和'store' 管理员:可以访问一切

仅供参考:'overview' 是一种索引视图,但仅适用于批准者角色及更高角色

你们认为最好的方法是什么?这是我到目前为止所做的,但它似乎不起作用:


内核.php

protected $middlewareGroups = [
...
    'approver+' => [
        \App\Http\Middleware\Approver::class,
        \App\Http\Middleware\Editor::class,
        \App\Http\Middleware\Admin::class,
    ],
];

protected $routeMiddleware = [
...
    'student' => \App\Http\Middleware\Student::class,
    'approver' => \App\Http\Middleware\Approver::class,
    'editor' => \App\Http\Middleware\Editor::class,
    'admin' => \App\Http\Middleware\Admin::class,
];

Http\Middleware\Admin.php

public function handle($request, Closure $next)

   if (Auth::check())
   

        if(Auth::user()->isAdmin())
        
            return $next($request);
        
   

    return redirect('login');


“用户”Eloquent 模型:

public function isAdmin()

    if($this->role_id === 4)
     
        return true; 
     
    else 
     
        return false; 
    

我在 Approver 和 Editor 中间件文件中做了完全相同的操作,在 User 模型的 isApprover 和 isEditor 函数中,只将 if 语句中的检查值分别编辑为 2 和 3。

最后,这是我在 routes\web 文件中所做的:

Route::get('scholen', 'SchoolsController@index');
Route::get('admin/scholen/overzicht', 'SchoolsController@overview')->middleware('approver+');
Route::get('admin/scholen/maken', 'SchoolsController@create')->middleware('approver+');
Route::post('scholen', 'SchoolsController@store')->middleware('approver+');
Route::get('scholen/id', 'SchoolsController@show');
Route::get('admin/scholen/id/bewerken', 'SchoolsController@edit')->middleware('admin');
Route::patch('admin/scholen/id', 'SchoolsController@update')->middleware('admin');
Route::delete('admin/scholen/id', 'SchoolsController@destroy')->middleware('admin');

这还不是很准确,但是当我以具有批准者权限的用户身份登录并尝试访问学校概览时,它会将我重定向回主页。

总的来说,感觉我的工作太混乱了,一点也不对,有人可以给我建议如何更有效地做吗?

非常感谢您!

【问题讨论】:

【参考方案1】:

您不应该为每个角色使用单独的中间件。它会很快变得非常混乱。最好有一个可以检查传递给它的任何角色的角色检查中间件。

Http\Kernel.php

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

Http\Middleware\Role.php

public function handle($request, Closure $next, ... $roles)

    if (!Auth::check()) // I included this check because you have it, but it really should be part of your 'auth' middleware, most likely added as part of a route group.
        return redirect('login');

    $user = Auth::user();

    if($user->isAdmin())
        return $next($request);

    foreach($roles as $role) 
        // Check if user has the role This check will depend on how your roles are set up
        if($user->hasRole($role))
            return $next($request);
    

    return redirect('login');

终于在你的网络路由中

Route::get('admin/scholen/overzicht', 'SchoolsController@overview')->middleware('role:editor,approver');
Route::get('admin/scholen/id/bewerken', 'SchoolsController@edit')->middleware('role:admin');

【讨论】:

我觉得我把它弄得太复杂了 :) 这似乎工作得很好,非常感谢! 3 个点“...”救了我的命 :) 那个操作员的名字是wiki.php.net/rfc/spread_operator_for_array 如果我想对管理员和编辑器路由进行分组并为两者使用不同的前缀怎么办?如果编辑者登录 URL 应该是 editor/dashboard,如果管理员登录 URL 应该是 admin/dashboard。我们能做到什么? @FosAvance 这个有趣的 3 点“...”被称为可用的常量表达式 => PHP 5.6.x ;) 有趣的哈! :p【参考方案2】:

这是对法菲奇回应的补充。

您在 IF 中使用 in_array 而不是使用 FOREACH,如下所示:

if (! in_array($user->hasRole($role), $roles) 
 // returns if you dont have permission

return $next($request);

【讨论】:

【参考方案3】:

为每个登录会话请求完成您的处理函数

public function handle($request, Closure $next)

    if (! Auth::check()) 
        return redirect()->route('login');
    

    if (Auth::user()->role == 1) 
        return redirect()->route('superadmin');
    

    if (Auth::user()->role == 5) 
        return redirect()->route('academy');
    

    if (Auth::user()->role == 6) 
        return redirect()->route('scout');
    

    if (Auth::user()->role == 4) 
        return redirect()->route('team');
    

    if (Auth::user()->role == 3) 
        return $next($request); 
    

    if (Auth::user()->role == 2) 
        return redirect()->route('admin');
    

【讨论】:

以上是关于具有多个角色的 Laravel 中间件的主要内容,如果未能解决你的问题,请参考以下文章

Laravel:以不同方式重定向不同的用户角色

如何在Laravel中将2个或更多用户角色分配给1个路由?

如何将控制器中的 Laravel 4.2 beforeFilter 转换为 Laravel 5.2 中的自定义中间件

php Laravel的多角色权限中间件

Laravel: 使用isAdmin列检查用户是否是管理员?

具有相同令牌的多个 Laravel-API 的 JWT 身份验证