问题
I am trying to set permission to access an action to two different user roles Admin, Normal_User as shown below.
Route::group(['middleware' => ['role_check:Normal_User','role_check:Admin']], function() {
Route::get('/user/{user_id}', array('uses' => 'UserController@showUserDashboard', 'as' => 'showUserDashboard'));
});
This route can be accessed by either Admin or Normal_user. But in this middleware configuration, user is required to be both Admin and Normal_User. How can I add OR condition in middleware parameter passing? Or is there any other method to give permission?
The following is my middleware
public function handle($request, Closure $next, $role)
{
if ($role != Auth::user()->user_role->role ) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
} else {
return response('Unauthorized.', 401);
}
}
return $next($request);
}
Can anyone please reply?
回答1:
To add multiple parameters, you need to seperate them with a comma:
Route::group(['middleware' => ['role_check:Normal_User,Admin']], function() {
Route::get('/user/{user_id}', array('uses' => 'UserController@showUserDashboard', 'as' => 'showUserDashboard'));
});
Then you have access them to in your middleware like so:
public function handle($request, Closure $next, $role1, $role2) {..}
The logic from there is up to you to implement, there is no automatic way to say "OR".
回答2:
Instead of adding multiple arguments to your handle method and having to update it every time you add a new role to your application, you can make it dynamic.
Middleware
/**
* Handle an incoming request.
*
* @param $request
* @param Closure $next
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function handle($request, Closure $next) {
$roles = array_slice(func_get_args(), 2); // [default, admin, manager]
foreach ($roles as $role) {
try {
Role::whereName($role)->firstOrFail(); // make sure we got a "real" role
if (Auth::user()->hasRole($role)) {
return $next($request);
}
} catch (ModelNotFoundException $exception) {
dd('Could not find role ' . $role);
}
}
Flash::warning('Access Denied', 'You are not authorized to view that content.'); // custom flash class
return redirect('/');
}
Route
Route::group(['middleware' => ['role_check:default,admin,manager']], function() {
Route::get('/user/{user_id}', array('uses' => 'UserController@showUserDashboard', 'as' => 'showUserDashboard'));
});
This will check if the authenticated user has at least one of the roles provided and if so, passes the request to the next middleware stack. Of course the hasRole() method and the roles themselves will need to be implemented by you.
回答3:
You can use the 3 dot (...) syntax in PHP 5.6+
Your middleware's handle function
public function handle($request, Closure $next, ...$roles)
{
foreach($roles as $role){
if ($request->user()->hasRole($role)){
return $next($request);
}
}
abort(404);
}
回答4:
In the middleware class
<?php
namespace App\Http\Middleware;
use Closure;
use function abort;
use function array_flip;
use function array_key_exists;
use function array_slice;
use function func_get_args;
class MustBeOFUserType
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$roles = array_slice(func_get_args(), 2); // ['admin', 'author']
//flip $roles to get ['admin' => 0, 'author' => 1];
if (!auth()->guest() && array_key_exists(auth()->user()->role->name, array_flip($roles))) {
return $next($request);
}
abort(423, 'Sorry you are not authrized !');
}
}
in the web.php OR route file
Route::get('/usertype', function() {
return response(['Accessed'], 200);
})->middleware([
'App\Http\Middleware\MustBeOFUserType:admin,author'
]);
Remember space on ':admin,author' like ':admin, author' will result into errors
For sanity check and if your a TDD person like I am use this to test the middleware
<?php
namespace Tests\Feature;
use App\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use function factory;
class MustBeOFUserTypeTest extends TestCase
{
use RefreshDatabase;
/** @test * */
public function it_accepts_the_admin()
{
$this->signIn(factory(User::class)->states('administrator')->create());
$this->get('/usertype')->assertStatus(200);
}
/** @test * */
public function it_rejects_normal_users()
{
$this->signIn();
$this->get('/usertype')->assertStatus(423);
}
/** @test **/
public function it_accepts_authors()
{
$this->signIn(factory(User::class)->states('author')->create());
$this->get('/usertype')->assertStatus(200);
}
public function signIn($user = null)
{
$u = $user ?: factory('App\User')->states('normal')->create();
$this->be($u);
return $this;
}
}
回答5:
//please take note there must be space between ... $roles
//on your route make sure there is no space in between the roles
'checkRole:staff,admin'
public function handle($request, Closure $next, ... $roles)
{
foreach($roles as $role){
if ($request->user()->hasRole($role)){
return $next($request);
}
}
abort(404);
}
you can try this out also
Route::group(['middleware' => 'role:webdev|admin'], function () {
});
public function handle($request, Closure $next, $role)
{
$roles = collect(explode('|',$role));
if (! $request->user()->hasRole($roles)) {
abort(404, 'No Way');
}
return $next($request);
}
来源:https://stackoverflow.com/questions/38712282/how-to-pass-multiple-parameters-to-middleware-with-or-condition-in-laravel-5-2