How to protect a route with middleware in laravel? - laravel

i have a problem with my middleware. when i login as admin, it's working fine and redirect to /Admin/home same as Operator (i have 2 user, Admin & Operator). The problem is when i hit url as example : /Operator/home as Admin role, it can access it. And that's the problem.
I'have create a new middleware CheckMiddleware, and registered to kernel in array $routeMiddleware as checkMiddleware:
public function handle($request, Closure $next)
{
$user = $request->user();
if ($user) {
if ($user->isAdmin()) {
return $next($request);
}elseif($user->isOperator()){
return $next($request);
}
}
return dd('Forbidden page. you have to login as admin/operator');
}
In the route :
Route::group(['prefix'=>'Admin' ,'middleware' => 'checkMiddleware'], function() {
Route::get('/home', 'HomeController#index')->name('homeAdmin');
});
Route::group(['prefix'=>'Operator' ,'middleware' => 'checkMiddleware'], function() {
Route::get('/home', 'HomeController#index')->name('homeAdmin');
});
Auth::routes();
in User model :
public function isAdmin(){
if ($this->role_id === 1) {
return true;
}
return false;
}
public function isOperator(){
if ($this->role_id === 2) {
return true;
}
return false;
}
What i want is, Admin cannot access Operator and Operator Cannot Access Admin.
if this is not clear, tell me what file you want to see.

The problem is if user is admin then accept request and user is operator still accept request. That code below
if ($user->isAdmin()) {
return $next($request);
}elseif($user->isOperator()){
return $next($request);
}
For simple solution, just create two middleware for admin and operator. Then apply admin middleware for route (group) need admin role, and apply operator middleware for route (group) need operator role.
If you have some route allow admin and operator role access, just add both to that route.
UPDATE
If you want to use 1 middleware, do like this :
if ($user->isAdmin() && $request->route()->getPrefix() == 'admin') {
return $next($request);
}
if ($user->isOperator() && $request->route()->getPrefix() == 'operator') {
return $next($request);
}
return abort(401) // OR SOME ROUTE YOU WANT

Related

Same route different middleware route group

Here is my super admin middleware,
if(Auth::user()->role_id == 1) {
return $next($request);
}
return redirect('/');
and,here is admin middleware,
if(Auth::user()->role_id == 2) {
return $next($request);
}
return redirect('/');
Here is my manager middleware,
if(Auth::user()->role_id == 3) {
return $next($request);
}
return redirect('/');
Here is my seller middleware,
if(Auth::user()->role_id == 4) {
return $next($request);
}
return redirect('/');
and, this is web.php,
Route::middleware(['superadmin'])->group(function () {
Route::resource('users', UserController::class);
//and more
});
Route::middleware(['admin'])->group(function () {
Route::resource('users', UserController::class);
//and more
});
Route::middleware(['manager'])->group(function () {
Route::resource('managers', ManagerController::class);
//and more
});
Route::middleware(['seller'])->group(function () {
Route::resource('sellers', SellersController::class);
//and more
});
I have 4types of middleware. Each route group have different route. Its working properly. Some of the routes are also used in another group. But then it doesn't work.
Doesn't make sense to have two different middleware here. What do you want to achieve? If the user is an admin then what and if user is a superadmin then what?
If the purpose is to just allow either admin or superadmin to access routes defined under the middleware group then a single middleware is enough.
//IsAdmin middleware
//if the user is either superadmin or admin allow else redirect
if(in_array(Auth::user()->role_id, [1,2])) {
//If you want to process based on whether admin or superadmin
//you can do it here
//if(Auth::user()->role_id ===1) {
// process when user is superadmin
// }
//else {
// process when user is admin
//}
return $next($request);
}
return redirect('/');
Then protect the routes in routes file
Route::middleware(['isAdmin'])->group(function () {
Route::resource('users', UserController::class);
});

Protecting Routes with Middleware in laravel

I have a project that it has two sections "admin" and "student".
I want to make a middleware that if a user who authenticated if his role was 1 automatically redirect it to admin panel and if his role was 2 automatically redirect it to student panel.
i made this middleware but when im test it i have "Too Many Rediredcts" error :
My Middleware Code :
if (auth()->check() && auth()->user()->role === 1){
return $next($request);
}else{
return redirect()->route('front.index');
}
My Routes :
How can i solve this?
I was facing the same issue and resolve it by using redirection with Url-like redirect('/admin/login'). Check and try the below code in your Laravel app.
if (auth()->check() && auth()->user()->role === 1){
return $next($request);
}else{
return redirect('/admin/login')->withErrors(['Access Denied']);
}
OR
if (auth()->check() && auth()->user()->role === 1){
return $next($request);
}else{
return redirect()->to('/admin/login')->withErrors(['Access Denied']);
}
Without seeing your middleware, it's hard to identify the problem, but the rest of your code looks fine. Try changing your your middleware to something like this:
public function handle(Request $request, Closure $next, string $roleName)
{
if (Auth::user()->isRole($roleName)) {
return $next($request);
}
abort(403);
}
We're passing a role into the middleware from the route, in your case you might pass admin. So any of your admin routes will now look like this:
Route::middleware('checkRole:admin')->prefix('admin')->group(function () {
Route::get('/', [BackController::class 'index'])->name('admin.index')
});
You are now passing a string variable to your middleware $roleName
Of course you'll also need to implement the isRole() method on your User.php Model. This will be something like:
/**
* #return HasOne
*/
public function role(): HasOne
{
return $this->hasOne(Role::class, 'id', 'role_id');
}
/**
* #return bool
*/
public function isRole($roleName): bool
{
$role = $this->role()->first();
if(!is_null($role) && $role->name == $roleName) {
return true;
}
return false;
}
I've made an assumption that you have a role_id column on your User.php Model, that you have a Role.php Model with name column which will match admin etc and you also have $routeMiddleware in Kernel.php something similar to 'checkRole' => checkRole::class,
Tested and working in Laravel 6/Laravel 8
If you wanted to test auth, I would update your route middleware to take an array, perhaps similar to:
['auth', 'checkRole:admin']
Where I have abort(403) you'll need a map of routes to roles, example: if you are an admin return redirect()->route('admin.index')

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 can i register multiple middleware permissions in routegroup?-Laravel

I have 3 roles roles, admin, tutor and student. i want to place them in 3 different goups, i however want the admin to be in all the groups. I have tried different methods to add the admin to other routes but it's not working. How can i make admin use all routes in tutor's middleware? Here is my code
AdminMiddleware, similar to all the others
class AdminMiddleware
{
public function handle($request, Closure $next)
{
if(Auth::check() && Auth::user()->isRole()=="admin") {
return $next($request);
}
return redirect('login');
}
}
routesmiddleware - in web.php
Route::group(['middleware'=>['auth'=>'admin']], function (){
//admin routes
}
Route::group(['middleware'=>['auth'=>'tutor']], function (){
//tutor routes
}
in the Kernel.php
'admin' => \App\Http\Middleware\AdminMiddleware::class,
'tutor' => \App\Http\Middleware\TutorMiddleware::class,
'student' => \App\Http\Middleware\StudentMiddleware::class,
in user model
public function isRole(){
return $this->role;
}
What you can do is define a middleware that takes the supported roles as argument:
class HasRoleMiddleware
{
public function handle($request, Closure $next, ...$roles)
{
if(Auth::check() && in_array(Auth::user()->getRole(), $roles)) {
return $next($request);
}
return redirect('login');
}
}
This middleware expects that User::getRole() returns the role as string, i.e. admin or tutor. Then you need to define the middleware in Kernel.php as you have already done:
'any_role' => \App\Http\Middleware\HasRoleMiddleware::class,
And finally you can use the middleware like this:
Route::group(['middleware' => 'auth'], function () {
Route::group(['middleware' => 'any_role:admin'], function () {
// admin routes
}
Route::group(['middleware' => 'any_role:admin,tutor'], function () {
// tutor routes
}
}
As you can see, I've also nested the route groups which perform role checks inside another route group which checks for authentication. This makes it more readable and reduces the risk you forget an authentication check in a future extension of your routes.

Laravel 5.2 Authentication error: Accessing logged in page directly through URL

I am using Laravel 5.2 and I have Authenticate.php file in:
\vendor\laravel\framework\src\Illuminate\Auth\Middleware
I need to authenticate my user so that, the user can't access the logged in page by just writing it in URL. How to do it?
When I searched, the solutions were for the Authenticate file which was in Middleware folder inside Http, which was a little different.
Please tell me how to do it. I tried:
if(Auth::guard($guard) -> guest()){
if ($request -> ajax()){
return response['Unauthorized',401];
} else{
return redirect() -> guest('login');
}
}
return $next($request);
}
}
How to do it? please tell me options. Any suggestion is invited.
And, Thank you in advance... :)
The solutions you found while searching are correct, you should actually edit your middlewares inside app/Http/Middleware if you checked out the documentation here, the right way to do it is:
You have to update this middleware app/Http/Middleware/RedirectIfAuthenticated.php which has this function
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/admin');
}
return $next($request);
}
What you can do in your case, you can use the same if clause in your current handle function, so it looks like this:
if (Auth::guard($guard)->check()) {
return redirect('/admin');
}
if (Auth::guard($guard)->guest()) {
if ($request->ajax()) {
return response['Unauthorized',401];
} else {
return redirect()->guest('login');
}
}
return $next($request);
Put all the routes that only the logged in users can access into Auth Middleware group:
Route::group(['middleware' => ['auth']], function () {
// Routes here
});

Resources