Laravel Middleware doesn't work properly for Role Middleware - php

I have a role middleware. when i pass to role from my controller as a string it's work properly but when pass as an array it's not working. This way middleware work properly.
$this->middleware('HasRole:User|Admin|Author')->except(['userEdit','roleEdit','permissionEdit','userUpdate']);
But when I change like this, it's not working.
$this->middleware('HasRole:User,Admin,Author')->except(['userEdit','roleEdit','permissionEdit','userUpdate']);
Here, is my middleware.
public function handle($request, Closure $next, ...$role)
{
$roles=is_array($role)? $role: explode('|', $role);
//dd($roles);
if($request->user()===null)
{
return response('Insufficient Access',401);
}
if($request->user()->hasAnyRole($roles) || !$roles)
{
return $next($request);
}
return response('Insufficient Permission',401);
//return $next($request);
}

controller
public function __construct()
{
$this->middleware('HasRole:User,Admin,Author')->except(['userEdit','roleEdit','permissionEdit','userUpdate']);
}
your middleware
read here http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list about the ...$
public function handle($request, Closure $next, ...$roles)
{
// $roles is array('User', 'Admin', 'Author')
// 0 => 'User',
// 1 => 'Admin',
// 2 => 'Author'
if($request->user()===null)
{
return response('Insufficient Access',401);
}
if($request->user()->hasAnyRole($roles) || !$roles)
{
return $next($request);
}
return response('Insufficient Permission',401);
//return $next($request);
}

Related

Add Multiple Middleware to Laravel Project

I'm new to laravel I have created middleware for my each role but when I add it to my route it won't work.
If I add single middleware to my route it works fine but when I add second and third one It will not work.
It won't shows the route to authorized user it redirect it to home,
My User Model:
public function IsAdmin()
{
if($this->role_id =='1')
{
return true;
}
else
{
return false;
}
}
public function IsManager()
{
if($this->role_id =='2')
{
return true;
}
else
{
return false;
}
}
public function IsUser()
{
if($this->role_id =='3')
{
return true;
}
else
{
return false;
}
}
My Kernal:
'IsAdmin' => \App\Http\Middleware\IsAdmin::class,
'IsManager' => \App\Http\Middleware\IsManager::class,
'IsUser' => \App\Http\Middleware\IsUser::class,
My IsAdmin Middlewares:
public function handle($request, Closure $next)
{
$user =Auth::User();
if(!$user->IsAdmin())
{
return redirect('stock');
}
return $next($request);
}
My IsManager
public function handle($request, Closure $next)
{
$user =Auth::User();
if(!$user->IsManager())
{
return redirect('stock');
}
return $next($request);
}
and IsUser
public function handle($request, Closure $next)
{
$user =Auth::User();
if(!$user->IsUser())
{
return redirect('stock');
}
return $next($request);
}
and finally my Route
Route::get('approv',['middleware'=>['IsManager','IsAdmin'],function(){
return view('approv');
}]);
This will not work as you'd expect. All middleware need to pass in order for the request to be processed which means that your user will need to be both a manager and an admin at the same time which based on your setup is impossible.
You can get around this (kind of) by making a different kind of middleware:
Kernel:
'roles' => \App\Http\Middleware\Roles::class,
And the Roles middleware:
class Roles {
private function checkRole($role) {
switch ($role) {
case 'user': return \Auth::user()->IsUser();
case 'manager': return \Auth::user()->IsManager();
case 'admin': return \Auth::user()->IsAdmin();
}
return false;
}
public function handle($request, Closure $next, ...$roles)
{
foreach ($roles as $role) {
if ($this->checkRole($role)) {
//At least one role passes
return $next($request);
}
}
//All checks failed so user does not have any of the required roles
return redirect('stock');
}
}
Then to use this you simply do:
Route::get('approv',['middleware'=>['roles:manager,admin'],function(){
return view('approv');
}]);
This works because Laravel Middleware support parameters. You can pass parameters as a comma separated list of strings where you declare the middleware. In this case this was done as roles:manager,admin
Laravel will then send these parameters as additional parameters in the handle method. These can be accessed using PHPs syntax for variadic arguments. In this particular case it's by using the array spread operator. This is documented as an example in the function arguments section of the PHP manual.
Note that this is actually equivalent to saying :
public function handle($request, Closure $next, $role1=null, $role2=null, $role3=null)
but using the spread operator is much more convenient since ...$roles would be an array which contains only the roles that were passed in the middleware.

How to send a string or an array to laravel middleware

I'm working on Laravel and try to make anACL system. I have a Role Middleware From myController I've sent Role to my RoleMiddleware two way.
first one is send string.
$this->middleware('HasRole:User|Admin|Author');
this way i'm get a string when use dd() function.
and the second way is.
$this->middleware('HasRole:User,Admin,Author');
this way i'm get an array when use dd() function.
but this array only contains a single value.
result like this.
array:1 [▼
0 => "User"
]
other two value Admin & Author doesn't appear in this array.
How can i work both way string & array
Here is my middleware.
public function handle($request, Closure $next,$role='')
{
$roles=is_array($role)? $role: explode('|', $role);
dd($roles);
if($request->user()===null)
{
return response('Insufficient Access',401);
}
if($request->user()->hasAnyRole($roles) || !$roles)
{
return $next($request);
}
return response('Insufficient Permission',401);
//return $next($request);
}
I know maybe not exactly the answer to your question, but I recommend you to use laravel authorization instead middleware. see this doc
I prefer to use this code for your problem in the controller:
$this->authorize('update', $post);
or:
if ($user->can('create', Post::class)) {
// Executes the "create" method on the relevant policy...
}
then inside the policy file, you should specify the statement like:
if ($user->isSuperAdmin() || $user->id === $post->user_id) {
return true;
}
if you want middleware to automatically convert your string to array then middleware $role params should be like this
public function handle($request, Closure $next, ...$roles)
{
dd($roles);
if($request->user()===null)
{
return response('Insufficient Access',401);
}
if($request->user()->hasAnyRole($roles) || !$roles)
{
return $next($request);
}
return response('Insufficient Permission',401);
//return $next($request);
}
Then use it like this $this->middleware('HasRole:User,Admin,Author');
OR
But if you want some other character to separate your roles like | then the code should be
public function handle($request, Closure $next, $role = '')
{
$roles = explode('|', $role);
dd($roles);
if($request->user()===null)
{
return response('Insufficient Access',401);
}
if($request->user()->hasAnyRole($roles) || !$roles)
{
return $next($request);
}
return response('Insufficient Permission',401);
//return $next($request);
}
And use it like $this->middleware('HasRole:User|Admin|Author');
You can use both, just add some code in your middleware.
public function handle($request, Closure $next,...$role)
{
//add two line
$str_role=explode('|',$role[0]);
$roleString=$str_role;
$roles=is_array($role)? $role : is_array($roleString)? $roleString : null;
//dd($roles);
if($request->user()===null)
{
return response('Insufficient Access',401);
}
if($request->user()->hasAnyRole($roles) || !$roles)
{
return $next($request);
}
return response('Insufficient Permission',401);
//return $next($request);
}
NOW, you can use.
$this->middleware('HasRole:User|Admin|Author');
OR,
$this->middleware('HasRole:User,Admin,Author');

Handling Admin and User Authentication - Laravel

I have 2 two users (Admin and operators) for my system and i want to authenticate them to their various pages based on their roles. I am using the Authenticated.php middleware to achieve this job like below
but i get an error when trying to login with any of the users as
Call to undefined method Illuminate\Contracts\Auth\Factory::check()
What am i doing wrong please?
Authenticated.php
public function handle($request, Closure $next, ...$guards)
{
if(Auth::check()) {
if(Auth::user()->hasRole('administrator')) {
return redirect('/');
} else if (Auth::user()->hasRole('operator')) {
return redirect('client/dashboard');
}
}
// $this->authenticate($guards);
return $next($request);
}
Route.php
Route::group(['middleware' => ['auth']], function () {
Route::get('/', 'PagesController#dashboard');
});
Route::group(array('prefix' => 'client', 'namespace' => 'User', 'middleware' => ['auth']), function () {
Route::get('/dashboard', 'DashboardController#create');
});
Aren't you messing up with your if condition? Try the below code in your RedirectIfAuthenticated.php file in App\Http\Middleware. Hope that will resolve your problem.
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
if(Auth::user()->hasRole('administrator'))
{
return redirect('/');
}
else
{
return redirect('client/dashboard');
}
}
return $next($request);
}
And Are you using Entrust for handling roles?

Laravel check if user has specific role before proceeding with other functions

I have a controller like this:
public function __construct()
{
$check = Auth::id();
if ($check->role == '5') {
// allow to run any other controller
} else {
// return view('home')
}
return $check;
}
public function index()
{
return view('admin.home');
}
What I want to do is whenever, AdminController is triggered, run __construct function and check if role == 5, if it is, proceed with the request, else return view. How can that be done?
Edit
public function handle($request, Closure $next)
{
if ($request->role == 2) {
} else {
return view('index');
}
return $next($request);
}
Kernel:
protected $middlewareGroups = [
'admin' => [
\App\Http\Middleware\CheckAdmin::class,
],
];
Route:
Route::group(['middleware' => ['admin']], function () {
Error::
(1/1) FatalThrowableError Call to a member function setCookie() on
null in VerifyCsrfToken.php (line 156)
view() returns a Illuminate\View\View object, instead of a Illuminate\Http\Response. So instead of sending the view. Redirect the user to index route
Try this
public function handle($request, Closure $next)
{
if ($request->role != 2) {
return return redirect()->route('index');
}
return $next($request);
}

Laravel 5.4 Middleware for Admin and User Role

I created two Middleware called "MustBeAdmin" and "MustBeUser" to make sure depending on the user login I redirect them to the right page and restrict unauthorized content. Currently everything is working fine and redirects work well too. But the Logic I wrote behind the scene seems wrong to me and its weird it still works. If I write the logic that seems right to me atleast, it does not seem to work as expected.
Users table
id (1,2,3,...)
name
role (1,2,3,...)
Roles table
id (1,2,3,...)
role (Student, Admin,...)
MustBeAdmin middleware
public function handle($request, Closure $next)
{
if($request->user()->role == 2)
{
return $next($request);
}
else
{
return redirect('/admin/users');
}
}
MustBeUser middleware:
public function handle($request, Closure $next)
{
if($request->user()->role == 1)
{
return $next($request);
}
else
{
return redirect('/admin/users');
}
}
kernel.php
'admin' => \App\Http\Middleware\MustBeAdmin::class,
'user' => \App\Http\Middleware\MustBeUser::class,
As you can see I have registered middlewares in kernel.
I am getting results exactly what I need but I doubt if the logic in middleware is correct?
1 = Student
2 = Admin
if you see in MustBeAdmin middleware I am comparing if user role is 2 (admin) then do next($request) and in MustBeUser middleware I am comparing if user role is 1 (Student) then do next($request) and I set else to /Admin directory.
I feel its wrong, what do you think?
You are not checking the authenticated users details in your Middleware. The middleware should be something like:
//for student
public function handle($request, Closure $next)
{
if ( Auth::check() && Auth::user()->role == 1 )
{
return $next($request);
}
return redirect('/admin');
}
//for admin
public function handle($request, Closure $next)
{
if ( Auth::check() && Auth::user()->role == 2 )
{
return $next($request);
}
return redirect('/student');
}
You should check my detailed answer on the same topic here
Yes, It can be handled in one common file.
Here is the code
public function handle($request, Closure $next)
{
$user = User::find(Auth::id());
$roles = [];
foreach ($user->roles as $key => $value) {
array_push($roles, $value->pivot->role_id);
}
$routeName = Route::getFacadeRoot()->current()->uri();
$route = explode('/', $routeName);
if ($route[0] == "teacher") {
if (in_array(2, $roles)) {
return $next($request);
} else {
return response('Unauthorized.', 401);
}
} elseif ($route[0] == "student") {
if (in_array(1, $roles)) {
return $next($request);
} else {
return response('Unauthorized.', 401);
}
} elseif ($route[0] == "admin") {
if (Auth::user()->admin == 1) {
return $next($request);
} else {
return response('Unauthorized.', 401);
}
} else {
if (!Auth::user()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('admin-panel/auth/login');
}
}
}
return $next($request);
}
You can alter the logic according to your need.

Categories