【问题标题】:Laravel 6 perform role based routingLaravel 6 执行基于角色的路由
【发布时间】:2020-07-10 00:40:59
【问题描述】:

我有一个包含不同路线的路线组。我希望在不更改应用程序 URL 的情况下拥有不同角色级别的访问权限。

例如,我想将 /admin 作为路由,然后我想根据用户的角色允许或禁止用户。基本上,我希望每个用户都能够看到相同的页面,但具有不同的菜单选项(我知道如何做到这一点),而且还能保护链接不被直接访问。

有没有一种很好的方法来实现这一点,而无需在每条路由上分别使用不同的中间件?由于似乎没有办法在 web.php 文件中检索 $request 变量,而只能在控制器内部检索。我正在使用 sentinel 包进行身份验证。

我的 web.php 的一些示例代码:

Route::group(
['prefix' => 'admin', 'middleware' => 'customer', 'as' => 'admin.'],
function () {
    // Ad list
    Route::get('getMyAnnonsList', 'Admin\BackEndController@getMyAdList')->name('getMyAdList');       
    }
);

@lagbox 的好答案。这就是我最后所做的。非常优雅。

web.php:

Route::group(['prefix' => 'admin', 'as' => 'admin.'], function () {
Route::middleware('admin:admin,user')->group(function(){
            Route::get('getMyAnnonsList', 'Admin\BackEndController@getMyAdList')->name('getMyAdList'); 
        });
});

中间件:

public function handle($request, Closure $next, ...$roles)
{      
    if (!Sentinel::check()) 
        return redirect('admin/signin')->with('info', 'You must be logged in!');
     
    foreach($roles as $role)        
        if($role == Sentinel::getUser()->roles[0]->slug)
            return $next($request);        
   
    return redirect()->back();  
}

【问题讨论】:

  • 你试过web.php文件中的request()辅助方法吗?甚至Route::group的?
  • 是的。 $request 变量在 web.php 上不包含身份验证信息。这是 Laravel 设计的:web.php->route->middleware->controller。所以我尝试在中间件中填充 request 变量并且它有效但它只能在控制器中访问,因为它在中间件之后不会返回到 web.php 文件。
  • 是的,我没有考虑过这个问题,但更具体地说,你似乎有一个问题是必须在“每条路由上”声明一个中间件,所以你没有使用资源路由、路由组、或者在 Controller::__constructor() 中声明中间件,这些都是为了减轻声明中间件的负担。如果这不是您的问题,请澄清。
  • 我不确定这里的实际问题是什么......你指的是什么不同的中间件?
  • 主要问题是我想在 web-php 文件中的路由组内允许不同的角色,然后根据用户角色允许访问不同的链接/路由。一种方法是使用 2 个不同的中间件创建同一个组,并在每个组中包含不同的路由。我想知道是否可以使用包含所有路由的单个组并使用简单的 if 语句来允许或禁止访问。

标签: laravel sentinel


【解决方案1】:

我之前已经回答过类似的问题,应该仍然可以正常工作。

您可以创建一个可应用于您的组的中间件。在该中间件中,它要求路由本身检查特定角色。

How to assign two middleware to the same group of routes. Laravel

中间件示例:

class CheckMiddleware
{
    public function handle($request, Closure $next)
    {
        $roles = $request->route()->getAction('roles', []);

        foreach ((array) $roles as $role) {
            // if the user has this role, let them pass through
            if (...) {
                return $next($request);
            }
        }

        // user is not one of the matching 'roles'
        return redirect('/');
    }
}

示例路由定义:

Route::middleware('rolescheck')->group(function () {
    Route::get('something', ['uses' => 'SomeController@method', 'roles' => [...]])->name(...);
});

您可以在组级别、单个路由级别或两者应用此任意数据,因为所有路由都是单独注册的;组只允许级联配置。

你也可以让这个中间件接受参数,然后将它们与任意角色合并,那么它就是一个双重用途的中间件:

public function handle($request, $next, ...$roles)
{
    $roles = array_merge($roles, $request->route()->getAction('roles', []));
    ...
}

Route::middleware('rolescheck:admin,staff')->group(...);

【讨论】:

  • 哇,这比我想象的还要好。很好的答案!
  • 希望对你有帮助:)
  • @m33ts4k0z 我添加了进一步的更新,允许您将其用作常规角色检查中间件,您也可以将参数传递给该中间件
  • 谢谢。我在这篇文章中测试了你的第一个例子,它就像一个魅力。我将在中间件组中使用您的最新示例,因为我有很多路由,并且需要一些时间来重写它们才能使用 ['uses' => ...] 格式。
  • 没问题,你有 3 种不同的方式来处理这 1 个中间件,所以你应该没问题......并且从链接的答案中确保注意它们如何级联,如果需要(它为每个嵌套组添加所有角色)
【解决方案2】:

您可以使用Laravel Gate And Policies

你可以在App > Providers > AuthServiceProvider里面定义门

您还可以根据CRUD 创建策略。只需查看php artisan help make:policy 中的信息即可。这将在您的 app 中创建一个名为策略的文件夹,您可以定义谁可以访问它。

在您的控制器中,您可以这样做:(这是一个门中间件)

我先定义门:

Gate::define('check', function ($user, $request) {
  return $user->roles->contains('name', $request) || $user->roles->contains('name', 'root');
});

然后我在控制器中初始化它

abort_if(Gate::denies('check', 'admin only'), 403);

如果用户无权访问该角色,这将引发 403 错误。它将检查用户是否具有admin only 角色。如果没有它会抛出错误

在您看来,如果您想禁用 anchor links,您可以这样做:

@can('check', 'admin only')
  <a href="/admin/dashboard">dashboard</a>
@endcan

编辑: 控制器

public function index() {
  abort_if(Gate::denies('check', 'admin only'), 403);
  // Your Code...
}

【讨论】:

  • 原来的问题仍然存在:这必须在控制器中完成,因为在 web.php 中选择路由时没有经过身份验证的用户
猜你喜欢
  • 2019-06-21
  • 2021-07-02
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
  • 2016-06-12
  • 2012-01-01
  • 1970-01-01
  • 2015-07-17
相关资源
最近更新 更多