Reputation: 1171
I've made a role middleware to check if user has a specific Role:
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);
}
}
If I want to check for some role in a specific role it's easy. I only have to add the middleware and an additional action called roles
. E. g.:
Route::get('payments/{id}/pay', [
'uses' => 'PaymentController@aprove',
'as' => 'payments.aprove',
'middleware' => 'roles',
'roles' => [User::ADMINISTRATOR, User::SPOT_MANAGER, User::SELECTION_PROCESS_MANAGER],
]);
Doing this way works as expected. However, I have some routes that are Route::resource
instead of get
, post
, or something like this. Laravel don't allow for specifying roles => [...]
in resource.
The documentation says that if I want to inject middleware on resources I should do this on controller. But I can't specify roles => [...]
as I used to do in normal routes anywhere! How could I do this?
Thanks in advance.
Upvotes: 0
Views: 252
Reputation: 50491
Since you dont have control over the 'action' array to use when defining resource routes, and the middleware paremeters are not fitting you can define your own ResourceRegistrar
and bind it to the container so the router will use it on Route::resource
calls.
You will extend Illuminate\Routing\ResourceRegistrar
and override the getResourceAction
method to check the $options
array to see if ... lets say a key named action
is defined. If so merge this array into the $action
array and now all the routes defined via Route::resource
can accept an options key of action
that takes your extra action values.
Allows for a definition like:
Route::resource('blah', 'BlahController', [
'action' => ['roles' => ['admin', 'editor']]
]);
Something like this 'should' do:
protected function getResourceAction($resource, $controller, $method, $options)
{
$action = parent::getResourceAction($resource, $controller, $method, $options);
if (isset($options['action'])) {
$action += $options['action'];
}
return $action;
}
In a service provider at register
the binding:
$this->app->bind(
\Illuminate\Routing\ResourceRegistrar::class,
\App\Your\ResourceRegistrar::class
);
You could take that further and make it specific to roles so you could do this instead:
Route::resource('blah', 'BlahController', ['roles' => ['admin', 'editor']]);
Upvotes: 1
Reputation: 50491
You can avoid this by using middleware parameters, so you can pass parameters to your middleware. This 'action' method is a nice work around for some things but middleware take paremeters so there really isn't a need unless you need those params in more places.
'middleware' => 'roles:admin,editor,...'
Literally the example for middleware parameters in the docs is a user role check.
Laravel 5.5 Docs - Middleware - Parameters
Also there is no 'injection'. You are just telling the router you want middleware, there isn't anything injected into anything else.
Upvotes: 1