Laravel Multiple Middleware cause redirect loop - php

I have a middleware group of auth inside that i want to apply another middleware to one specific route in that view that is if the profile is not completed user cant go to any other route until he complete his profile and submit.
More Specifically, middle ware is causing loop on redirect because i have 2 middleware.
i created middleware with laravel php artisan and checking the user if profile is incomplete he should redirect to the profile/edit page but its not even working with just check on incomplete empty companyname.
Middlware
class incompleteProfile
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(empty(Auth::user()->details['companyname'])){
return redirect()->route('profile');
}
return $next($request);
}
}
Routes File
Routes
Route::group(['middleware'=>['auth'] ], function(){
// User Profile
Route::get('/profile/edit', 'UserController#profile')->name('profile')->middleware('incompleteProfile');
Route::post('/profile/edit', 'UserController#editProfile')->name('editProfile');

If you put that middleware on the profile route ... how can they ever get to the profile route to get the form to update the profile to add the missing information?
You are saying ... if user details for company name are empty, then redirect to profile, but you have that middleware on profile ... so its going to forever redirect to profile because the middleware is telling it to. Your user can never get to profile in this case.
This is the equivalent of assigning the auth middleware to the login page. The auth middleware checks if the user is currently authenticated. Which means if a user is not authenticated they would never be able to get to login, in this scenario, as login requires them to be "logged in".

lagbox answer pretty much says the logic of why it doesn't work.
Try it like this.
Route::group(['middleware'=>['auth'] ], function(){
// User Profile
Route::get('/profile/edit', 'UserController#profile')->name('profile');
Route::group(['middleware'=>['incompleteProfile'] ], function(){
Route::post('/profile/edit', 'UserController#editProfile')->name('editProfile');
//ETC
});
});

Related

Laravel 8 Auth::logoutOtherDevices always redirect to login route

I use Auth::logoutOtherDevices to make sure that 1 user only can use 1 device. So when he login from another devices and authenticated, the other device will logout and redirect to form login. I already redirect to form login to my route "auth.show", but it alwasy redirect to route "login" first which i dont have. then after i refresh it will redirect to route "auth.show". so the problem is it alwasy redirect to route login. i also tried to dd("tes") on the middleware and same result, alwasy redirect to route login, then show the "test". what is the problem ?
here my Authenticate middleware
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* #param \Illuminate\Http\Request $request
* #return string|null
*/
protected function redirectTo($request)
{
if (!$request->expectsJson()) {
return route('auth.show');
}
}
}
You need just to add a route with name called login to your routes like this
Route::get('login',[Controller::class,'yourMethod'])>name('login');
to refer to the login page in your application.

Limit a view to only invited users Laravel Middleware

I am looking for a way to show a specific view only to specific visitors who get a link to that view. How can I make a middleware so that shows the view only if it comes from a specific source (like if it comes from source.blade.php)
I cannot use the middleware for guest or auth, because then it would give that view to all the auth, but I only want give that view to an auth who has made a payment at beginning and have been redirected from a specific URL.
How can I setup a middleware in such a way that it only shows the view if the auth is being redirected from another view like - source.blade.php
Currently, I have this page setted up like this
public function __construct()
{
$this->middleware('auth:client');
}
This works well, it only shows this page to someone who has logged in from the client authentication guard, but the problem is, any client can visit this page.
I am looking for a way to make it so that it can viewed only by the client who paid at the beginning, and were re-directed by my website. Maybe something like
public function __construct()
{
if(redirect_source="source.blade.php") {$this->middleware('auth:client'); }
}
I think you want a solution that will limit the permission based on your user type.
Middlewares are used to condition certain parameters if you want to let the requester to go into the specific url/route and not to control inside your views.
So if you want to control it, you can use this solution .
namespace App\Laravel\Middleware\Backoffice;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\RedirectResponse;
use Auth, Session;
class ValidSuperUser {
/**
* The Guard implementation.
*
* #var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if($this->auth->user()->type != "super_user") {
Session::flash('notification-status','failed');
Session::flash('notification-title',"Access Denied");
Session::flash('notification-msg','You are not allowed to view the page you are tring to access.');
return redirect()->route('backoffice.dashboard');
}
return $next($request);
}
}
in your Kernel.php under Http folder declare the new Middleware in order to use.
**put it under protected $routeMiddleware = []
and then use it to your routes that need to help that kind of user type.
$route->group(['middleware' => "aliasofyournewmiddle"],function(){
//some routes here
});
your new middleware can be any condition upon the request, so any inputs and available session that has been passed to that url are usable on that middleware, adjust it on how you want to handle the situation.
You can pass a token when redirecting your users to your specific page. Then use your middleware to check whether that token is valid or not.
Say for example, someone made a payment at beginning, you store a hash value of that person's user id or any unique identifier in a session, then redirect the user with the same hash value included in your url. Your middleware can then handle the validation, if the value stored in the session is the same with the value provided in the url.

Laravel multiple user types

Below description is based on Laravel development.
A brief description of the functionality I am hoping to achieve is,
There are 3 types of users. Superadmin, Admin and Enduser.
Only one Superadmin exist and he can create both Admins and Endusers. There can be multiple Admins exist and an admin is defined for a given site. An admin can create multiple Endusers.
To facilitate above use case, what sort of approach should I take in Laravel?
My attempt to accomplish this so far is:
I implemented multiple guards and then I was stuck since there are some routes which should be accessible by all types of users. I couldn't get it done with multiple guards since if I define multiple guards for a route, that route is only accessible only if all the multiple user types are logged in.
Say, I have a route guarded by Superadmin and Admin, this route is not available only if I logged in as Superadmin. Route is available only if both Superadmin and Admin are logged in.
Seems if we assign multiple guards, guards are ANDed. But I need them to be ORed.
guard assignment:
Route::group(['middleware' => ['auth:superadmin', 'auth:admin']], function() {...
Instead of Guards, I would separate out the SuperAdmin, Admin, and EndUser into individual middleware that performs a simple role check. For example a SuperAdmin middleware:
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::user()->isSuperAdmin) {
return $next($request);
}
abort(404);
}
then regular Admin
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::user()->isSuperAdmin || Auth::user()->isAdmin) {
return $next($request);
}
abort(404);
}
and then finally a simple check for authenticated users, i.e. EndUser
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::check()) {
return $next($request);
}
abort(404);
}
Then you can apply the middle to your groups as needed.
Route::group(['middleware' => ['superadmin']], function() {...
Route::group(['middleware' => ['admin']], function() {...
Route::group(['middleware' => ['enduser']], function() {...
By your logic, a Superadmin is always an admin, and an Admin is also an Enduser. If you start with opening routes in nested level you can get this work like.
Route::group(['middleware' => ['auth:enduser']], function(){
// All the routes available for Enduser
// For Admin
Route::group(['middleware' => ['auth:admin']], function(){
// Give admin routes here
//Create group for SuperAdmin
Route::group(['middleware'=>['auth:superadmin']], function(){
// Super admin routes
});
});
});
This way Superadmin had everything accessabile.
I managed to get it solved. No multiple guards. As #anwerj pointed out, all the users are type ENDUSER
Added user_type as an attribute to User model. SUPERADMIN, ADMIN and ENDUSER are the three user types. It is different from user role since a user can take multiple roles whereas once a user designated as ADMIN, will be ADMIN forever and he can have special privileges.
Implemented authorization mechanism where a route can be granted either
to a single user (i.e. only the granted user can have access to the particular route) or
to a user role (not the user_type mentioned above. A user role might have multiple users)
Routes were grouped to permission_set. A user_role can have multiple permission_sets
When a user logs in, middleware checks whether the resource being requested is granted for the User.
You can pass multiple arguments to a piece of middleware like this.
$this->group(['middleware' => ['restricted.role:super-admin,admin']], function () {
// ...
});
The RestrictedRole middleware class handle method will look like this.
public function handle($request, Closure $next, ...$roles)
{
if (Auth::user()->inRoles($roles)) {
return response()->json(['error' => "You don't have access to that"], 401);
}
return $next($request);
}
Finally, the User class will implement an inRole method like this.
public function inRoles($roles)
{
return in_array($this->getAttribute('role'), $roles);
}
You can also nest routes and restrict roles further like this.
$this->group(['middleware' => ['restricted.role:super-admin,admin']], function () {
// super-admin and admin can access this block of routes.
$this->group(['middleware' => ['restricted.role:super-admin']], function () {
// Only super-admin can access this block of routes.
});
});

What is middleware in laravel?

I'm trying to understand how the middleware works in Laravel. Here's my class can any one explain how does its works.?
<?php
namespace App\Http\Middleware;
use Closure;
class CheckAge
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($request->age <= 200) {
return redirect('home');
}
return $next($request);
}
}
Thanks
Middleware provide a convenient mechanism for filtering HTTP requests entering your application. For example, Laravel includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.
Reference
Edit: As explained by #num8er
Middleware is the function (or logic) that stands between router and route handler.
In your code:
public function handle($request, Closure $next)
{
if ($request->age <= 200) {
return redirect('home');
}
return $next($request);
}
$request->age is a variable that provided in request and can be checked on each HTTP request, if its value <= 200 then user redirects to home route.
As you can see what the middleware is, now lets see the code
public function handle($request, Closure $next)
{
if ($request->age <= 200) {
return redirect('home');
}
return $next($request);
}
This code check every request and check the age variable in the request. If the age is less than 200 then the request will be redirect to the home otherwise it will go to the requesting page. Suppose you are requesting /about page but if you can not pass the middleware condition you will be redirected to /home otherwise to /about i.e. given by return $next($request);. Similary works with auth and cors middleware. You can similarly do some check like $request->user->role=='admin' and redirect to admin page or to other page.
return $next($request); this gives you the next requesting route (the original route that have requested)
Middleware provide a convenient mechanism for filtering HTTP requests entering your application. For example, Laravel includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.
Of course, additional middleware can be written to perform a variety of tasks besides authentication. A CORS middleware might be responsible for adding the proper headers to all responses leaving your application. A logging middleware might log all incoming requests to your application.
https://laravel.com/docs/5.4/middleware#introduction
Middleware is a series of wrappers around your application that decorate the requests and the responses in a way that isn't a part of your application logic.
https://mattstauffer.co/blog/laravel-5.0-middleware-filter-style
Middleware main objective is to restrict the unwanted action and here you can check the user given input values and you can allow is valid only.

how to disable the url for specific user in laravel?

I have an admins table that has some columns like id, admin_type, name, etc. Here I have two types of admin_type: one is "admin" and the other is "hod".
Now the problem is that I want admins that login with (admin_type == "admin") to be able to access all the admin URLs, but when admin_type == "hod" I want to limit the URLs the user can access.
I am using Laravel 5.2. Can anyone help me to resolve this issue?
For example, if a user with admin_type=="hod" accesses these links
www.example.com/admin/add-user
www.example.com/admin/edit-user
www.example.com/admin/add-customer
www.example.com/admin/edit-customer
and many more URLs, I want to show some message like **You have no rights to access this link **
Here is my database structure:
I would implemented a Middleware for such a use case. Just execute php artisan make:middleware yourNameHere in your Laravel working directory and artisan generates the corresponding middleware class for you.
Then you need code like this. It's a simple if condition with an 403 abort in case that the user is no admin.
class AdminMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($request->user()->admin_type != 'admin') {
return abort(403, "No access here, sorry!");
}
return $next($request);
}
}
Your routes file (routes/web.php):
...
Route::group(["middleware" => 'admin'], function () {
//Your admin routes should be declared here
});
...

Categories