在控制器上注入路由操作
Inject Route Action on Controller
我制作了一个角色中间件来检查用户是否具有特定角色:
namespace App\Http\Middleware;
use Closure;
class CheckRole
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->user() === null) {
return response("Insufficient permissions", 401);
}
$actions = $request->route()->getAction();
$roles = isset($actions['roles']) ? $actions['roles'] : null;
if ($request->user()->hasAnyRole($roles) || !$roles) {
return $next($request);
}
return response("Insufficient permissions", 401);
}
}
如果我想检查特定角色中的某个角色,这很容易。我只需添加中间件和一个名为 roles
的附加操作。例如:
Route::get('payments/{id}/pay', [
'uses' => 'PaymentController@aprove',
'as' => 'payments.aprove',
'middleware' => 'roles',
'roles' => [User::ADMINISTRATOR, User::SPOT_MANAGER, User::SELECTION_PROCESS_MANAGER],
]);
按照预期的方式进行操作。但是,我有一些路线是 Route::resource
而不是 get
、post
或类似的路线。 Laravel 不允许在资源中指定 roles => [...]
。
文档说如果我想在资源上注入中间件我 should do this on controller。但是我不能像以前在任何地方的正常路线中那样指定 roles => [...]
!我该怎么做?
提前致谢。
您可以通过使用中间件参数来避免这种情况,因此您可以将参数传递给您的中间件。这种 'action' 方法对于某些事情来说是一个很好的解决方法,但是中间件需要参数,所以除非你在更多地方需要这些参数,否则真的没有必要。
'middleware' => 'roles:admin,editor,...'
从字面上看,文档中中间件参数的示例是用户角色检查。
Laravel 5.5 Docs - Middleware - Parameters
也没有'injection'。你只是告诉路由器你想要中间件,没有任何东西注入到其他任何东西中。
由于您在定义资源路由时无法控制要使用的 'action' 数组,并且中间件参数不合适,您可以定义自己的 ResourceRegistrar
并将其绑定到容器,以便路由器将在 Route::resource
次通话中使用它。
您将扩展 Illuminate\Routing\ResourceRegistrar
并覆盖 getResourceAction
方法来检查 $options
数组以查看是否...假设定义了一个名为 action
的键。如果是这样,将这个数组合并到 $action
数组中,现在所有通过 Route::resource
定义的路由都可以接受一个 action
的选项键,它采用你的额外操作值。
允许这样的定义:
Route::resource('blah', 'BlahController', [
'action' => ['roles' => ['admin', 'editor']]
]);
像这样'should'做:
protected function getResourceAction($resource, $controller, $method, $options)
{
$action = parent::getResourceAction($resource, $controller, $method, $options);
if (isset($options['action'])) {
$action += $options['action'];
}
return $action;
}
在 register
的服务提供商中绑定:
$this->app->bind(
\Illuminate\Routing\ResourceRegistrar::class,
\App\Your\ResourceRegistrar::class
);
您可以更进一步,使其特定于角色,这样您就可以改为这样做:
Route::resource('blah', 'BlahController', ['roles' => ['admin', 'editor']]);
我制作了一个角色中间件来检查用户是否具有特定角色:
namespace App\Http\Middleware;
use Closure;
class CheckRole
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->user() === null) {
return response("Insufficient permissions", 401);
}
$actions = $request->route()->getAction();
$roles = isset($actions['roles']) ? $actions['roles'] : null;
if ($request->user()->hasAnyRole($roles) || !$roles) {
return $next($request);
}
return response("Insufficient permissions", 401);
}
}
如果我想检查特定角色中的某个角色,这很容易。我只需添加中间件和一个名为 roles
的附加操作。例如:
Route::get('payments/{id}/pay', [
'uses' => 'PaymentController@aprove',
'as' => 'payments.aprove',
'middleware' => 'roles',
'roles' => [User::ADMINISTRATOR, User::SPOT_MANAGER, User::SELECTION_PROCESS_MANAGER],
]);
按照预期的方式进行操作。但是,我有一些路线是 Route::resource
而不是 get
、post
或类似的路线。 Laravel 不允许在资源中指定 roles => [...]
。
文档说如果我想在资源上注入中间件我 should do this on controller。但是我不能像以前在任何地方的正常路线中那样指定 roles => [...]
!我该怎么做?
提前致谢。
您可以通过使用中间件参数来避免这种情况,因此您可以将参数传递给您的中间件。这种 'action' 方法对于某些事情来说是一个很好的解决方法,但是中间件需要参数,所以除非你在更多地方需要这些参数,否则真的没有必要。
'middleware' => 'roles:admin,editor,...'
从字面上看,文档中中间件参数的示例是用户角色检查。
Laravel 5.5 Docs - Middleware - Parameters
也没有'injection'。你只是告诉路由器你想要中间件,没有任何东西注入到其他任何东西中。
由于您在定义资源路由时无法控制要使用的 'action' 数组,并且中间件参数不合适,您可以定义自己的 ResourceRegistrar
并将其绑定到容器,以便路由器将在 Route::resource
次通话中使用它。
您将扩展 Illuminate\Routing\ResourceRegistrar
并覆盖 getResourceAction
方法来检查 $options
数组以查看是否...假设定义了一个名为 action
的键。如果是这样,将这个数组合并到 $action
数组中,现在所有通过 Route::resource
定义的路由都可以接受一个 action
的选项键,它采用你的额外操作值。
允许这样的定义:
Route::resource('blah', 'BlahController', [
'action' => ['roles' => ['admin', 'editor']]
]);
像这样'should'做:
protected function getResourceAction($resource, $controller, $method, $options)
{
$action = parent::getResourceAction($resource, $controller, $method, $options);
if (isset($options['action'])) {
$action += $options['action'];
}
return $action;
}
在 register
的服务提供商中绑定:
$this->app->bind(
\Illuminate\Routing\ResourceRegistrar::class,
\App\Your\ResourceRegistrar::class
);
您可以更进一步,使其特定于角色,这样您就可以改为这样做:
Route::resource('blah', 'BlahController', ['roles' => ['admin', 'editor']]);