Laravel 9 multiple middleware in route - laravel

I have this route, that should work for both middlewares
Route::middleware(['company', 'consultant'])->group(function () {
Route::resource('/tasks', TaskController::class);
});
If I do
Route::middleware(['consultant'])->group(function () {
Route::resource('/tasks', TaskController::class);
});
Or
Route::middleware(['company'])->group(function () {
Route::resource('/tasks', TaskController::class);
});
Both work, yet the first example with both it does work just for the company.
In routeMiddleware I have as expected
'consultant' => \App\Http\Middleware\IsConsultant::class,
'company' => \App\Http\Middleware\IsCompany::class,
And in the Middleware folder
class IsCompany
{
public function handle(Request $request, Closure $next)
{
if (Auth::user() && Auth::user()->type == 2) {
return $next($request);
}
return redirect('dashboard')->with('error','You have not admin access');
}
}
class IsConsultant
{
public function handle(Request $request, Closure $next)
{
if (Auth::user() && Auth::user()->type == 1) {
return $next($request);
}
return redirect('dashboard')->with('error','You have not admin access');
}
}

If you want both of the middleware to succeed and pass the request, they won't. They are mutually exclusive, since one needs Auth::user()->type == 2 and other Auth::user()->type == 1
If one succeeds, the other has to fail by definition.
You can rather have a single middleware with in_array(Auth::user()->type, [1, 2], true) that'd work when the user type is either 1 or 2, if that's what you're looking for.

Related

Protecting Routes With Two middle-wares So that both users can access it

I am trying to protect a route using two middle-wares so that both expert and user can access the same route but as soon a user tries to access the route he is logged out.
I had created two middle-wares for expert and user and protect the route using these middle-wares.
Web.php
Route::group(['middleware' => ['expert','user']], function () {
Route::post('/showForm','UserController#showFormFilled');
});
User Middle ware
public function handle($request, Closure $next)
{
//////////////////// check if user is logged in ///////////////////
if(Auth::check())
{
////////////////// check user role id //////////////////////////
if(auth()->user()->role_id == 3)
{
return $next($request);
}
else if (auth()->user()->role_id==2)
{
return redirect('/expert');
}
}
else
{
return redirect('/login');
}
}
Expert Middle ware
public function handle($request, Closure $next)
{
if(Auth::check()){
if(auth()->user()->role_id == 2)
return $next($request);
else if (auth()->user()->role_id==3)
return redirect('/dashboard');
}
else {
return redirect('/login');
}
}
Both the users should be able to access the same route.
#hamzahummam - there is no way to achieve what you are looking for using the above separate-middlware-for-each-type method. Each middleware prematurely redirects [either to /dashboard or to /expert etc] the request without allowing it to passthrough other middleware. Best would be to use a third-party package that provides a more comprehensive and fine-grained access control [example: https://github.com/Zizaco/entrust]
If that's not an option, the best case would be to implement a single middleware and pass the role as parameter. See: Laravel Middleware Parameters
A minimal example would look like:
public function handle($request, Closure $next, $role)
{
// Assuming Auth::check() passes
$roleId = auth()->user()->role_id;
if ($roleId == 2 && strpos($role, 'expert') !== false) {
// Logged in user is `expert` and route allows `expert` access
return $next($request);
} else if ($roleId == 3 && strpos($role, 'user') !== false) {
// Logged in user is `user` and route allows `user` access
return $next($request);
} // and so on...
// Handle failures here
if ($roleId == 2 && strpos($role, 'expert') === false) {
// an `expert` is trying to access route that can't be accessed
return redirect('/expert-dashboard');
} // and so on...
}
You'd define routes as:
Route::group(['middleware' => ['new_middleware:expert,user' ]], function () {
Route::post('/showForm','UserController#showFormFilled');
});
Hope this helps.

How to get id in Middleware when i use user()

I have a relationship between users and roles. In middleware, I need to get roles to check if the role is 1 or 2. However, I get the following error.
"Trying to get property 'role_id' of non-object."
I am sure I have id 1 in role_id.
User Model
public function role()
{
return $this->belongsTo(Role::class, 'role_id');
}
public function handle($request, Closure $next)
{
if (!Auth()->check() && $request->user()->role_id == 1) {
return redirect()->back();
}
return $next($request);
}
Your if statement's logic is mistakenly checking if the user is logged out, while also checking the user's roles. If Auth::check() is false, then the user is not logged in and $request->user() will return null.
Removing the ! from the conditional will fix the error you're receiving.
public function handle($request, Closure $next)
{
if (Auth()->check() && $request->user()->role_id == 1) {
return redirect()->back();
}
return $next($request);
}
However, this will allow all guests to proceed, which you may not want. Assuming you want the middleware to only allow logged-in users with a specific role to proceed, use a more white-listed approach like this:
public function handle($request, Closure $next)
{
// Role ID 2 has permission to proceed
if (Auth()->check() && $request->user()->role_id == 2) {
return $next($request);
}
// Everyone else should go back, including logged-in users and guests.
return redirect()->back();
}
[Can't comment so I'm making a post.]
Aken already answered you but I'd suggest one more thing. Don't use 1 or 2 as ID's but constants:
public function handle($request, Closure $next)
{
if (Auth()->check() && $request->user()->role_id == ADMIN) {
return $next($request);
}
return redirect()->back();
}
You don't even need the comments for this one. Maybe even better:
public function handle($request, Closure $next)
{
if (Auth()->check() && $request->user()->isAdmin()) {
return $next($request);
}
return redirect()->back();
}
but you need to implement it on your own.

Having an issue with Multiple middleware in laravel

I am trying to process 2 middleware before routing it to controller. Laravel won't give me an error on the following code but it only processes the 1st middleware 'CheckReferer' and won't process the 2nd middleware 'CheckCart'. It process the 1st middleware even if you change the sequence (e.g 'CheckCart', 'CheckReferer').
web.php
Route::prefix($language)->middleware('CheckReferer', 'CheckCart')->group(function() {
Route::get('/', 'HomeController#getIndex')->name('home');
});
CheckReferer.php (Middleware)
class CheckReferer
{
public function handle($request, Closure $next)
{
$Referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
if($Referer != null) {
$url_parsed = parse_url($Referer);
if ($url_parsed['host'] == 'www.example.com') {
$Referer = true;
Session::put('Referer', $Referer);
}
}
return $next($request);
}
}
CheckCart.php (Middleware)
class CheckCart
{
public function handle(Request $request, Closure $next)
{
$oldCart = Session::has('Cart') ? Session::get('Cart') : null;
return $next($request);
}
}
Pass them as array...
Route::prefix($language)->middleware(['CheckReferer', 'CheckCart'])->group(function() {
Route::get('/', 'HomeController#getIndex')->name('home');
});

How to write or use two levels of user permissions at once?

I have two levels in middleware and it does not work well, then how to write middleware in two levels at once?
public function __construct()
{
$this->middleware('auth');
$this->middleware('Admin');
$this->middleware('Teacher');
}
I also have this, i want to check that this page is only accessible by admin and teacher, but in writing the code it does not work well and how to write it right?
#if (Auth::check() && Auth::user()->level == 'Admin')
#elseif (Auth::check() && Auth::user()->level == 'Teacher')
#endif
If you can help me in solving this problem i am very grateful
in my experience i did that using a middleware ..
Middleware
public function handle($request, Closure $next, $roles)
{
$roles = explode('|',$roles);
$user = User::find($request->user()->id);
foreach($user->intRoles as $myRole)
{
if(in_array($myRole->role_id, $roles))
{
return $next($request);
}
}
return redirect()->back();
}
Route
Route::group( ['middleware' => 'rolePermissions:1|2|3'], function(){
Route::get('/users',['as'=>'users', 'uses'=>'PagesController#users']);
});
mydomain.com/users will only be accessible for those users who have roles (id) of 1, 2, or 3 ..
You have 2 separate middleware for checking user level. This forces both the conditions and doesn't work the way you want. You need a single middleware to check the user level and pass parameters to it.
Assume we have this middleware named as access.
public function handle($request, Closure $next, $levels)
{
$userLevels = explode(',', $levels);
if (Auth::check() && in_array(Auth::user()->level, $userLevels)) {
return $next($request);
}
return redirect('/home');
}
In your controller add this
public function __construct()
{
$this->middleware(['auth', 'access:Admin,Student']);
}

StaffMiddleware And AdminMiddleware Laravel 5.3

I have 2 Middlewares.
My StaffMiddleware
public function handle($request, Closure $next)
{
if( $request->user()->role->name != 'staff'){
return redirect()->route('store');
}
return $next($request);
}
My AdminMiddleware
public function handle($request, Closure $next)
{
if( $request->user()->role->name != 'admin'){
return redirect()->route('store');
}
return $next($request);
}
The Problem is my UnitController
public function __construct(UnitInterface $unit){
$this->middleware('staff');
$this->middleware('admin);
$this->unit = $unit;
}
It should work either the role is a staff or an admin. Do I need to create another Middleware to combine them both?
This completely depends on the way your Middleware is designed. As you can see from your code, it simple redirects if the role is not staff or not admin so there would be no way for you to have an OR logic.
However, you could use middleware parameters to avoid this.
$this->middleware('role:admin,staff');
This will use the role middleware and pass admin and staff as parameters.
Then you can use these parameters in your middleware:
public function handle($request, Closure $next, ...$params)
{
if(!in_array($request->user()->role->name, $params)){
return redirect()->route('store');
}
return $next($request);
}
This captures the additional parameters into an array $params in which you can check if the user's role matches one of the parameters.
**try this**
public function __construct(UnitInterface $unit){
$this->middleware(function ($request, $next) {
if($request->user()->role->name == 'staff' || $request->user()->role->name == 'admin')
{
return $next($request);
}
return redirect()->route('store')
});
}
No middleware

Resources