Pass an array to a middleware in laravel - php

I got this handle in a middleware called rolMiddleware:
public function handle($request, Closure $next, $roles)
{
//dd($request->user());
foreach ($roles as $rol) {
if ($request->user()->getTipoUsuario($request->user()->tipo_usuario_id)->getNombreTipoUsuario() == $rol) {
return $next($request);
}
}
abort(403, "¡No hay autorizacion!");
}
But $roles is an array, here is the route where I use the middleware:
Route::get('/mid', ['middleware' => 'roles:super admin', function () {
return "done";
}]);
and the error that gives me is:
ErrorException in RolMiddleware.php line 22:
Invalid argument supplied for foreach()
You may thing that I do not need an array because I am only using it in super admin, for that route I only need super admin, but there would be routes that can be for super admin and the admin of an area.

In laravel , you can separate your parameters which you want to pass to middleware using comma , as follows:
Route::get('/mid', ['middleware' => 'roles:super,admin', function () {
// ^ note this
return "done";
}]);
note that, this won't send parameters as an array, so you can't loop over $roles unless you use your passed parameters as ellipsis parameters as follows :
public function handle($request, Closure $next, ...$roles)
rather, you will need to use a single parameter for each role:
public function handle($request, Closure $next, $role1, $role2) // .... and so on

Route:
Route::get('/access', ['middleware' => 'hasroles:super,admin', function () {
}]);
passing one parameter to check user have created permission in my
cause
Route::middleware('admin')->namespace('Admin')->prefix('admin')->group(function(){
Route::get('/home', 'MainController#getIndex')->name('admin.index')->middleware("hasrole:create");
Middleware:
1.Using Parameters
public function handle($request, Closure $next, $parm1, $parm2){}
2.Using var-arg
public function handle($request, Closure $next, $parm1, $parm2){}
public function handle($request, Closure $next, ...$parm1){}
Two-way Middleware Use
1: Register routeMiddleware
// Within App\Http\Kernel Class...
protected $routeMiddleware = [
'hasrole' => \Illuminate\Auth\Middleware\HasRole::class,
Using:
Route::get('admin/profile', function () {
})->middleware('hasrole');
2: Not Register in routeMiddleware
Using:
use App\Http\Middleware\HasRole;
Route::get('admin/profile', function () {
//
})->middleware(HasRole::class);

Send parameter as string like as
Route::prefix('panel')->middleware('auth:admin|editor')->group(function (){
Route::get('/', [SiteController::class, 'index'])->name('site.index');
}
Program in middleware to sense this string as array
if (in_array(Auth::user()->rule, explode('|', $access))) {
return $next($request);
} else {
return redirect()->route('site.denied');
}

I don't exactly understand what your functions do, but you can try something like this:
public function handle($request, Closure $next, $roles)
{
if(is_array($roles)){
//dd($request->user());
foreach ($roles as $rol) {
if ($request->user()->getTipoUsuario($request->user()->tipo_usuario_id)->getNombreTipoUsuario() == $rol) {
return $next($request);
}
}
}else{
if($request->user()->getTipoUsuario($request->user()->tipo_usuario_id)->getNombreTipoUsuario() == $roles)
return $next($request);
}
abort(403, "¡No hay autorizacion!");
}

You can use explode function within middleware for converting string to array.
Controller:
public function __construct()
{
$this->middleware('RoleCheck:admin|user')->except(['index', 'show']);
}
Middleware:
public function handle(Request $request, Closure $next, $roles)
{
$user = Auth::user();
$roles = explode("|", $roles); // convert $roles to array
foreach ($roles as $role) {
if ($user->hasRole($role))
return $next($request);
}
return redirect('login');
}

Related

Laravel 8.8 redirectTo function does't work

I need to implement logic when authorizing a user and I planned to do this in the redirectTo() function in the LoginController. However, Laravel does not seem to see it and always redirects to the HOME constant.
It seems that all files are correct.
LoginController
protected function redirectTo()
{
return redirect('/test');
}
auth-backend/RedirectsUsers
public function handle(Request $request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
return redirect('/account');
}
}
return $next($request);
}
Some users have found that the redirect happens in the middleware/RedirectIfAuthenticated, but I don't know how to fix it. If in this file I replace return redirect(RouteServiceProvider::HOME) with some path, for example redirect('/account') then it returns /account. But I still need to be in the redirectTo() function.
Middleware/RedirectIfAuthenticated
public function handle(Request $request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
return redirect('/account');
}
}
return $next($request);
}
How can I make the process come to redirectTo() after authorization?
Define a route in web.php for redirectTo function in Login Controller
Route::get('check-auth', [LoginController::class, 'redirectTo'])->name('auth.redirect-to');
return to the route
return redirect()->route('auth.redirect-to');
make sure to use the LoginController on the top of web.php

i get undefined method error when i use IsAdmin middleware in Laravel

//here is my route
Route::get('/works', function () {
$works=Work::all();
return view('works',compact('works')); })->middleware('IsAdmin');
});
here is my IsAdmin function in User Model
public function roles(){
return $this->belongsToMany('App\Role','user_role','user_id','role_id');
}
public function IsRole(){
return $this->roles;
}
And this is my IsAdmin middleware
public function handle($request, Closure $next)
{
$user=Auth::user();
if($user->IsRole()->name=='Administrator'){
return true;
}
}
why it give me undefined method error?
do you register your middleware inside app/Kernel.php into $routeMiddleware array.
Should be something like that
protected $routeMiddleware = ['check.admin' => \App\Http\Middleware\YourClass::class]

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.

Laravel - How to pass variables to middleware through route group?

This is my route group,
Route::group(['middleware' => 'checkUserLevel'], function () {
// my routes
});
And this is my middleware checkUserLevel,
public function handle($request, Closure $next, $level)
{
$user = Auth::user();
if ($user->level > $level) {
return redirect('testUrl');
}
return $next($request);
}
I want to pass the $level variale to middleware from route group.
Thanks.
You can simply pass multiple arguments into the middleware using a colon. Use it like:
Route::group(['middleware' => 'checkUserLevel:some_value_of_level'], function () {
// my routes
});
Now, you can have this value inside your $level variable.
public function handle($request, Closure $next, $level)
{
$user = Auth::user();
if ($user->level > $level) {
return redirect('testUrl');
}
return $next($request);
}
This would help.
Edit: 14 Dec 2018
You can also send multiple variables to middleware. You just need to seperate the values using a comma (,).
Route::group(['middleware' => 'checkUserLevel:some_value_of_level, one_more_value_to_send'], function () {
// my routes
});
And you will get the value one_more_value_to_send in the variable after $level in the middleware handler.
public function handle($request, Closure $next, $level, $another_value)
{
$user = Auth::user();
if ($user->level > $level) {
return redirect('testUrl');
}
return $next($request);
}
For more details you can refer to: Passing parameters to Middleware in Laravel 5.1
In Laravel 6.x you have to do this
add code like in your middleware
public function handle($request, Closure $next,$module=null,$right=null)
{
dd($module,$right);
return $next($request);
}
your route code like this
Route::get('/department/add', 'DepartmentController#addNew')->middleware('ManualSec:abc,xyz');
In Kernel.php register your middleware in the section of $routeMiddleware like
'ManualSec' => \App\Http\Middleware\ManualSec::class,
by calling the rout using url in my case
http://local.pms.com:8080/department/add
it will result is like:
now you can code in your middleware

How to retrieve a url parameter from request in Laravel 5?

I want to perform certain operations with a model in a middleware. Here is an example of what I want to achieve:
public function handle($request, Closure $next)
{
$itemId = $request->param('item'); // <-- invalid code, serves for illustration purposes only
$item = Item::find($itemId);
if($item->isBad()) return redirect(route('dont_worry'));
return $next($request);
}
My question is, how can I retrieve the desired parameter from the $request?
public function handle(Request $request, Closure $next)
{
$itemId = $request->item;
//..............
}
If the parameter is part of a URL and this code is being used in Middleware, you can access the parameter by it's name from the route given:
public function handle($request, Closure $next)
{
$itemId = $request->route()->getParameter('item');
$item = Item::find($itemId);
if($item->isBad()) return redirect(route('dont_worry'));
return $next($request);
}
This is based on having a route like: '/getItem/{item}'
Use this after Laravel 5.5
public function handle($request, Closure $next)
{
$item = Item::find($request->route()->parameter('item'));
if($item->isBad()) return redirect(route('dont_worry'));
return $next($request);
}

Categories